diff --git a/libraries/libstratosphere/include/stratosphere/dd.hpp b/libraries/libstratosphere/include/stratosphere/dd.hpp index dc14d77b4..a089ed302 100644 --- a/libraries/libstratosphere/include/stratosphere/dd.hpp +++ b/libraries/libstratosphere/include/stratosphere/dd.hpp @@ -16,5 +16,7 @@ #pragma once -#include "dd/dd_io_mappings.hpp" -#include "dd/dd_process_handle.hpp" +#include +#include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space.hpp new file mode 100644 index 000000000..0ae119401 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space.hpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include + +#include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_api.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_api.hpp new file mode 100644 index 000000000..31d7148d8 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_api.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include +#include +#include +#include + +namespace ams::dd { + + Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 address, u64 size); + Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 size); + void DestroyDeviceAddressSpace(DeviceAddressSpaceType *das); + + void AttachDeviceAddressSpaceHandle(DeviceAddressSpaceType *das, Handle handle, bool managed); + + Handle GetDeviceAddressSpaceHandle(DeviceAddressSpaceType *das); + + Result MapDeviceAddressSpaceAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm); + Result MapDeviceAddressSpaceNotAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm); + void UnmapDeviceAddressSpace(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address); + + void InitializeDeviceAddressSpaceMapInfo(DeviceAddressSpaceMapInfo *info, DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm); + + Result MapNextDeviceAddressSpaceRegion(size_t *out_mapped_size, DeviceAddressSpaceMapInfo *info); + void UnmapDeviceAddressSpaceRegion(DeviceAddressSpaceMapInfo *info); + + u64 GetMappedProcessAddress(DeviceAddressSpaceMapInfo *info); + DeviceVirtualAddress GetMappedDeviceVirtualAddress(DeviceAddressSpaceMapInfo *info); + size_t GetMappedSize(DeviceAddressSpaceMapInfo *info); + + Result AttachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name); + void DetachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name); + +} diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp new file mode 100644 index 000000000..13676348f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include +#include + +namespace ams::dd { + + using DeviceName = ::ams::svc::DeviceName; + + constexpr inline u64 DeviceAddressSpaceMemoryRegionAlignment = 4_KB; + +} diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_types.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_types.hpp new file mode 100644 index 000000000..7de417fb7 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_types.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include +#include + +namespace ams::dd { + + using DeviceVirtualAddress = u64; + + using DeviceAddressSpaceHandle = ::Handle; + + struct DeviceAddressSpaceType { + enum State { + State_NotInitialized = 0, + State_Initialized = 1, + }; + DeviceAddressSpaceHandle device_handle; + u8 state; + bool is_handle_managed; + }; + static_assert(std::is_trivial::value); + + struct DeviceAddressSpaceMapInfo { + size_t last_mapped_size; + size_t size; + u64 process_address; + DeviceVirtualAddress device_start_address; + DeviceVirtualAddress device_end_address; + ProcessHandle process_handle; + MemoryPermission device_permission; + DeviceAddressSpaceType *device_address_space; + }; + static_assert(std::is_trivial::value); + +} diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp index c0f3ac992..c3f2d11b8 100644 --- a/libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp @@ -19,10 +19,6 @@ namespace ams::dd { - u32 ReadRegister(dd::PhysicalAddress phys_addr); - void WriteRegister(dd::PhysicalAddress phys_addr, u32 value); - u32 ReadWriteRegister(dd::PhysicalAddress phys_addr, u32 value, u32 mask); - /* Convenience Helper. */ inline uintptr_t GetIoMapping(dd::PhysicalAddress phys_addr, size_t size) { const uintptr_t io_mapping = dd::QueryIoMapping(phys_addr, size); diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp index 6688682de..2f06ef2eb 100644 --- a/libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp @@ -13,12 +13,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #pragma once #include +#include namespace ams::dd { - ::Handle GetCurrentProcessHandle(); + ProcessHandle GetCurrentProcessHandle(); } diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_types.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_types.hpp new file mode 100644 index 000000000..2d1587296 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_types.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include + +namespace ams::dd { + + using ProcessHandle = ::Handle; + + enum MemoryPermission { + MemoryPermission_None = 0, + MemoryPermission_ReadOnly = (1u << 0), + MemoryPermission_WriteOnly = (1u << 1), + + MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly, + }; + +} diff --git a/libraries/libstratosphere/source/dd/dd_device_address_space.cpp b/libraries/libstratosphere/source/dd/dd_device_address_space.cpp new file mode 100644 index 000000000..43f6fee04 --- /dev/null +++ b/libraries/libstratosphere/source/dd/dd_device_address_space.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include +#include "impl/dd_device_address_space_impl.hpp" + +namespace ams::dd { + + Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 address, u64 size) { + /* Check pre-conditions. */ + AMS_ASSERT(util::IsAligned(address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); + AMS_ASSERT(size > 0); + + /* Ensure we leave in a consistent state. */ + auto state_guard = SCOPE_GUARD { das->state = DeviceAddressSpaceType::State_NotInitialized; }; + + /* Create the address space. */ + DeviceAddressSpaceHandle handle; + R_TRY(impl::DeviceAddressSpaceImpl::Create(std::addressof(handle), address, size)); + + /* Set the values in the das. */ + das->device_handle = handle; + das->is_handle_managed = true; + das->state = DeviceAddressSpaceType::State_Initialized; + + /* We succeeded. */ + state_guard.Cancel(); + return ResultSuccess(); + } + + Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 size) { + return CreateDeviceAddressSpace(das, 0, size); + } + + void DestroyDeviceAddressSpace(DeviceAddressSpaceType *das) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + + /* Destroy the handle. */ + if (das->is_handle_managed) { + impl::DeviceAddressSpaceImpl::Close(das->device_handle); + } + + das->device_handle = 0; + das->is_handle_managed = false; + das->state = DeviceAddressSpaceType::State_NotInitialized; + } + + void AttachDeviceAddressSpaceHandle(DeviceAddressSpaceType *das, Handle handle, bool managed) { + /* Check pre-conditions. */ + AMS_ASSERT(handle != svc::InvalidHandle); + + das->device_handle = handle; + das->is_handle_managed = managed; + das->state = DeviceAddressSpaceType::State_Initialized; + } + + Handle GetDeviceAddressSpaceHandle(DeviceAddressSpaceType *das) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + + return das->device_handle; + } + + Result MapDeviceAddressSpaceAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + AMS_ASSERT(util::IsAligned(process_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(device_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); + AMS_ASSERT(process_address + size > process_address); + AMS_ASSERT(device_address + size > device_address); + AMS_ASSERT(size > 0); + AMS_ASSERT((process_address & (4_MB - 1)) == (device_address & (4_MB - 1))); + + return impl::DeviceAddressSpaceImpl::MapAligned(das->device_handle, process_handle, process_address, size, device_address, device_perm); + } + + Result MapDeviceAddressSpaceNotAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + AMS_ASSERT(util::IsAligned(process_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(device_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); + AMS_ASSERT(process_address + size > process_address); + AMS_ASSERT(device_address + size > device_address); + AMS_ASSERT(size > 0); + + return impl::DeviceAddressSpaceImpl::MapNotAligned(das->device_handle, process_handle, process_address, size, device_address, device_perm); + } + + void UnmapDeviceAddressSpace(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + AMS_ASSERT(util::IsAligned(process_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(device_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); + AMS_ASSERT(process_address + size > process_address); + AMS_ASSERT(device_address + size > device_address); + AMS_ASSERT(size > 0); + + return impl::DeviceAddressSpaceImpl::Unmap(das->device_handle, process_handle, process_address, size, device_address); + } + + void InitializeDeviceAddressSpaceMapInfo(DeviceAddressSpaceMapInfo *info, DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + AMS_ASSERT(util::IsAligned(process_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(device_address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); + AMS_ASSERT(process_address + size > process_address); + AMS_ASSERT(device_address + size > device_address); + AMS_ASSERT(size > 0); + + info->last_mapped_size = 0; + info->process_address = process_address; + info->size = size; + info->device_start_address = device_address; + info->device_end_address = device_address + size; + info->process_handle = process_handle; + info->device_permission = device_perm; + info->device_address_space = das; + } + + Result MapNextDeviceAddressSpaceRegion(size_t *out_mapped_size, DeviceAddressSpaceMapInfo *info) { + /* Check pre-conditions. */ + AMS_ASSERT(info->last_mapped_size == 0); + + size_t mapped_size = 0; + if (info->device_start_address < info->device_end_address) { + R_TRY(impl::DeviceAddressSpaceImpl::MapPartially(std::addressof(mapped_size), info->device_address_space->device_handle, info->process_handle, info->process_address, info->size, info->device_start_address, info->device_permission)); + } + + info->last_mapped_size = mapped_size; + *out_mapped_size = mapped_size; + return ResultSuccess(); + } + + void UnmapDeviceAddressSpaceRegion(DeviceAddressSpaceMapInfo *info) { + /* Check pre-conditions. */ + const size_t last_mapped_size = info->last_mapped_size; + AMS_ASSERT(last_mapped_size > 0); + + impl::DeviceAddressSpaceImpl::Unmap(info->device_address_space->device_handle, info->process_handle, info->process_address, last_mapped_size, info->device_start_address); + + info->last_mapped_size = 0; + info->process_address += last_mapped_size; + info->device_start_address += last_mapped_size; + } + + u64 GetMappedProcessAddress(DeviceAddressSpaceMapInfo *info) { + return info->process_address; + } + + DeviceVirtualAddress GetMappedDeviceVirtualAddress(DeviceAddressSpaceMapInfo *info) { + return info->device_start_address; + } + + size_t GetMappedSize(DeviceAddressSpaceMapInfo *info) { + return info->last_mapped_size; + } + + Result AttachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + + return impl::DeviceAddressSpaceImpl::Attach(das, device_name); + } + + void DetachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name) { + /* Check pre-conditions. */ + AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); + + return impl::DeviceAddressSpaceImpl::Detach(das, device_name); + } + +} diff --git a/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp new file mode 100644 index 000000000..de47bec3f --- /dev/null +++ b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include + +#if defined(ATMOSPHERE_OS_HORIZON) + #include "dd_device_address_space_impl.os.horizon.hpp" +#else + #error "Unknown os for dd::DeviceAddressSpaceImpl" +#endif 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 new file mode 100644 index 000000000..e485de164 --- /dev/null +++ b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include +#include "dd_device_address_space_impl.os.horizon.hpp" + +namespace ams::dd::impl { + + static_assert(static_cast(dd::MemoryPermission_None) == static_cast(svc::MemoryPermission_None)); + static_assert(static_cast(dd::MemoryPermission_ReadOnly) == static_cast(svc::MemoryPermission_Read)); + static_assert(static_cast(dd::MemoryPermission_WriteOnly) == static_cast(svc::MemoryPermission_Write)); + static_assert(static_cast(dd::MemoryPermission_ReadWrite) == static_cast(svc::MemoryPermission_ReadWrite)); + + Result DeviceAddressSpaceImplByHorizon::Create(DeviceAddressSpaceHandle *out, u64 address, u64 size) { + /* Create the space. */ + svc::Handle handle; + R_TRY_CATCH(svc::CreateDeviceAddressSpace(std::addressof(handle), address, size)) { + R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) + R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + *out = static_cast(handle); + return ResultSuccess(); + } + + void DeviceAddressSpaceImplByHorizon::Close(DeviceAddressSpaceHandle handle) { + const auto svc_handle = svc::Handle(handle); + if (svc_handle == svc::PseudoHandle::CurrentThread || svc_handle == svc::PseudoHandle::CurrentProcess) { + return; + } + + R_ABORT_UNLESS(svc::CloseHandle(svc_handle)); + } + + Result DeviceAddressSpaceImplByHorizon::MapAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm) { + /* 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_CONVERT(svc::ResultInvalidHandle, dd::ResultInvalidHandle()) + R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) + R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) + R_CONVERT(svc::ResultInvalidCurrentMemory, dd::ResultInvalidMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + return ResultSuccess(); + } + + 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_CONVERT(svc::ResultInvalidHandle, dd::ResultInvalidHandle()) + R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) + R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) + R_CONVERT(svc::ResultInvalidCurrentMemory, dd::ResultInvalidMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + return ResultSuccess(); + } + + Result DeviceAddressSpaceImplByHorizon::MapPartially(size_t *out_mapped_size, DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm) { + ams::svc::Size mapped_size = 0; + R_TRY_CATCH(svc::MapDeviceAddressSpace(std::addressof(mapped_size), svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address, static_cast(device_perm))) { + R_CONVERT(svc::ResultInvalidHandle, dd::ResultInvalidHandle()) + R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) + R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) + R_CONVERT(svc::ResultInvalidCurrentMemory, dd::ResultInvalidMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + *out_mapped_size = mapped_size; + return ResultSuccess(); + } + + void DeviceAddressSpaceImplByHorizon::Unmap(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address) { + R_ABORT_UNLESS(svc::UnmapDeviceAddressSpace(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address)); + } + + Result DeviceAddressSpaceImplByHorizon::Attach(DeviceAddressSpaceType *das, DeviceName device_name) { + R_TRY_CATCH(svc::AttachDeviceAddressSpace(static_cast(device_name), svc::Handle(das->device_handle))) { + R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + return ResultSuccess(); + } + + void DeviceAddressSpaceImplByHorizon::Detach(DeviceAddressSpaceType *das, DeviceName device_name) { + R_ABORT_UNLESS(svc::DetachDeviceAddressSpace(static_cast(device_name), svc::Handle(das->device_handle))); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.hpp b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.hpp new file mode 100644 index 000000000..86225d430 --- /dev/null +++ b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include + +namespace ams::dd::impl { + + class DeviceAddressSpaceImplByHorizon { + public: + static Result Create(DeviceAddressSpaceHandle *out, u64 address, u64 size); + static void Close(DeviceAddressSpaceHandle handle); + + static Result MapAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm); + static Result MapNotAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm); + static Result MapPartially(size_t *out_mapped_size, DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm); + static void Unmap(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address); + + static Result Attach(DeviceAddressSpaceType *das, DeviceName device_name); + static void Detach(DeviceAddressSpaceType *das, DeviceName device_name); + }; + + using DeviceAddressSpaceImpl = DeviceAddressSpaceImplByHorizon; + +} \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/results.hpp b/libraries/libvapours/include/vapours/results.hpp index b69533be7..f10e5af32 100644 --- a/libraries/libvapours/include/vapours/results.hpp +++ b/libraries/libvapours/include/vapours/results.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libvapours/include/vapours/results/dd_results.hpp b/libraries/libvapours/include/vapours/results/dd_results.hpp new file mode 100644 index 000000000..d64a49181 --- /dev/null +++ b/libraries/libvapours/include/vapours/results/dd_results.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include + +namespace ams::dd { + + R_DEFINE_NAMESPACE_RESULT_MODULE(6); + + R_DEFINE_ERROR_RESULT(EndOfQuery, 1); + R_DEFINE_ERROR_RESULT(InvalidCurrentMemory, 2); + R_DEFINE_ERROR_RESULT(NotSingleRegion, 3); + R_DEFINE_ERROR_RESULT(InvalidMemoryState, 4); + R_DEFINE_ERROR_RESULT(OutOfMemory, 5); + R_DEFINE_ERROR_RESULT(OutOfResource, 6); + R_DEFINE_ERROR_RESULT(NotSupported, 7); + R_DEFINE_ERROR_RESULT(InvalidHandle, 8); + + R_DEFINE_ERROR_RESULT(InternalError, 1023); + +} diff --git a/stratosphere/boot/source/boot_display.cpp b/stratosphere/boot/source/boot_display.cpp index 67cba618c..254de4639 100644 --- a/stratosphere/boot/source/boot_display.cpp +++ b/stratosphere/boot/source/boot_display.cpp @@ -31,21 +31,21 @@ namespace ams::boot { namespace { /* Helpful defines. */ - constexpr size_t DeviceAddressSpaceAlignSize = 0x400000; - constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1; - constexpr uintptr_t FrameBufferPaddr = DisplayConfigFrameBufferAddress; - constexpr size_t FrameBufferWidth = 768; + constexpr size_t DeviceAddressSpaceAlignSize = 4_MB; + + constexpr dd::DeviceVirtualAddress FrameBufferDeviceAddress = DisplayConfigFrameBufferAddress; + + constexpr size_t FrameBufferWidth = 768; constexpr size_t FrameBufferHeight = 1280; - constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32); + constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32); - constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400; - - constexpr uintptr_t Disp1Base = 0x54200000ul; - constexpr uintptr_t DsiBase = 0x54300000ul; - constexpr uintptr_t ClkRstBase = 0x60006000ul; - constexpr uintptr_t GpioBase = 0x6000D000ul; - constexpr uintptr_t ApbMiscBase = 0x70000000ul; - constexpr uintptr_t MipiCalBase = 0x700E3000ul; + constexpr dd::PhysicalAddress PmcBase = 0x7000E400ul; + constexpr dd::PhysicalAddress Disp1Base = 0x54200000ul; + constexpr dd::PhysicalAddress DsiBase = 0x54300000ul; + constexpr dd::PhysicalAddress ClkRstBase = 0x60006000ul; + constexpr dd::PhysicalAddress GpioBase = 0x6000D000ul; + constexpr dd::PhysicalAddress ApbMiscBase = 0x70000000ul; + constexpr dd::PhysicalAddress MipiCalBase = 0x700E3000ul; constexpr size_t Disp1Size = 3 * os::MemoryPageSize; constexpr size_t DsiSize = os::MemoryPageSize; @@ -54,9 +54,9 @@ namespace ams::boot { constexpr size_t ApbMiscSize = os::MemoryPageSize; constexpr size_t MipiCalSize = os::MemoryPageSize; - constexpr s32 DsiWaitForCommandMilliSecondsMax = 250; - constexpr s32 DsiWaitForCommandCompletionMilliSeconds = 5; - constexpr s32 DsiWaitForHostControlMilliSecondsMax = 150; + constexpr int DsiWaitForCommandMilliSecondsMax = 250; + constexpr int DsiWaitForCommandCompletionMilliSeconds = 5; + constexpr int DsiWaitForHostControlMilliSecondsMax = 150; constexpr size_t GPIO_PORT3_CNF_0 = 0x200; constexpr size_t GPIO_PORT3_OE_0 = 0x210; @@ -66,32 +66,40 @@ namespace ams::boot { constexpr size_t GPIO_PORT6_OE_1 = 0x514; constexpr size_t GPIO_PORT6_OUT_1 = 0x524; - /* Types. */ - /* Globals. */ constinit bool g_is_display_intialized = false; - constinit u32 *g_frame_buffer = nullptr; constinit spl::SocType g_soc_type = spl::SocType_Erista; + constinit u32 g_lcd_vendor = 0; - constinit Handle g_dc_das_hnd = INVALID_HANDLE; constinit int g_display_brightness = 100; + + constinit dd::DeviceAddressSpaceType g_device_address_space; + + constinit u32 *g_frame_buffer = nullptr; constinit u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize]; - constinit uintptr_t g_disp1_regs = 0; - constinit uintptr_t g_dsi_regs = 0; - constinit uintptr_t g_clk_rst_regs = 0; - constinit uintptr_t g_gpio_regs = 0; + constinit uintptr_t g_disp1_regs = 0; + constinit uintptr_t g_dsi_regs = 0; + constinit uintptr_t g_clk_rst_regs = 0; + constinit uintptr_t g_gpio_regs = 0; constinit uintptr_t g_apb_misc_regs = 0; constinit uintptr_t g_mipi_cal_regs = 0; /* Helper functions. */ - void InitializeRegisterBaseAddresses() { - g_disp1_regs = dd::GetIoMapping(Disp1Base, Disp1Size); - g_dsi_regs = dd::GetIoMapping(DsiBase, DsiSize); - g_clk_rst_regs = dd::GetIoMapping(ClkRstBase, ClkRstSize); - g_gpio_regs = dd::GetIoMapping(GpioBase, GpioSize); - g_apb_misc_regs = dd::GetIoMapping(ApbMiscBase, ApbMiscSize); - g_mipi_cal_regs = dd::GetIoMapping(MipiCalBase, MipiCalSize); + void InitializeRegisterVirtualAddresses() { + g_disp1_regs = dd::QueryIoMapping(Disp1Base, Disp1Size); + g_dsi_regs = dd::QueryIoMapping(DsiBase, DsiSize); + g_clk_rst_regs = dd::QueryIoMapping(ClkRstBase, ClkRstSize); + g_gpio_regs = dd::QueryIoMapping(GpioBase, GpioSize); + g_apb_misc_regs = dd::QueryIoMapping(ApbMiscBase, ApbMiscSize); + g_mipi_cal_regs = dd::QueryIoMapping(MipiCalBase, MipiCalSize); + + AMS_ABORT_UNLESS(g_disp1_regs != 0); + AMS_ABORT_UNLESS(g_dsi_regs != 0); + AMS_ABORT_UNLESS(g_clk_rst_regs != 0); + AMS_ABORT_UNLESS(g_gpio_regs != 0); + AMS_ABORT_UNLESS(g_apb_misc_regs != 0); + AMS_ABORT_UNLESS(g_mipi_cal_regs != 0); } inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) { @@ -128,34 +136,38 @@ namespace ams::boot { void InitializeFrameBuffer() { if (g_frame_buffer != nullptr) { std::memset(g_frame_buffer, 0x00, FrameBufferSize); - armDCacheFlush(g_frame_buffer, FrameBufferSize); + dd::FlushDataCache(g_frame_buffer, FrameBufferSize); } else { - const uintptr_t frame_buffer_aligned = ((reinterpret_cast(g_frame_buffer_storage) + DeviceAddressSpaceAlignMask) & ~uintptr_t(DeviceAddressSpaceAlignMask)); + const uintptr_t frame_buffer_aligned = util::AlignUp(reinterpret_cast(g_frame_buffer_storage), DeviceAddressSpaceAlignSize); g_frame_buffer = reinterpret_cast(frame_buffer_aligned); + std::memset(g_frame_buffer, 0x00, FrameBufferSize); - armDCacheFlush(g_frame_buffer, FrameBufferSize); + dd::FlushDataCache(g_frame_buffer, FrameBufferSize); /* Create Address Space. */ - R_ABORT_UNLESS(svcCreateDeviceAddressSpace(&g_dc_das_hnd, 0, (1ul << 32))); + R_ABORT_UNLESS(dd::CreateDeviceAddressSpace(std::addressof(g_device_address_space), 0, (UINT64_C(1) << 32))); + /* Attach it to the DC. */ - R_ABORT_UNLESS(svcAttachDeviceAddressSpace(svc::DeviceName_Dc, g_dc_das_hnd)); + R_ABORT_UNLESS(dd::AttachDeviceAddressSpace(std::addressof(g_device_address_space), svc::DeviceName_Dc)); /* Map the framebuffer for the DC as read-only. */ - R_ABORT_UNLESS(svcMapDeviceAddressSpaceAligned(g_dc_das_hnd, dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr, 1)); + R_ABORT_UNLESS(dd::MapDeviceAddressSpaceAligned(std::addressof(g_device_address_space), dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferDeviceAddress, dd::MemoryPermission_ReadOnly)); } } void FinalizeFrameBuffer() { if (g_frame_buffer != nullptr) { - const uintptr_t frame_buffer_aligned = reinterpret_cast(g_frame_buffer); + const uintptr_t frame_buffer_aligned = util::AlignUp(reinterpret_cast(g_frame_buffer), DeviceAddressSpaceAlignSize); /* Unmap the framebuffer from the DC. */ - R_ABORT_UNLESS(svcUnmapDeviceAddressSpace(g_dc_das_hnd, dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr)); + dd::UnmapDeviceAddressSpace(std::addressof(g_device_address_space), dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferDeviceAddress); + /* Detach address space from the DC. */ - R_ABORT_UNLESS(svcDetachDeviceAddressSpace(svc::DeviceName_Dc, g_dc_das_hnd)); - /* Close the address space. */ - R_ABORT_UNLESS(svcCloseHandle(g_dc_das_hnd)); - g_dc_das_hnd = INVALID_HANDLE; + dd::DetachDeviceAddressSpace(std::addressof(g_device_address_space), svc::DeviceName_Dc); + + /* Destroy the address space. */ + dd::DestroyDeviceAddressSpace(std::addressof(g_device_address_space)); + g_frame_buffer = nullptr; } } @@ -192,7 +204,7 @@ namespace ams::boot { void InitializeDisplay() { /* Setup globals. */ - InitializeRegisterBaseAddresses(); + InitializeRegisterVirtualAddresses(); g_soc_type = spl::GetSocType(); InitializeFrameBuffer();