From 75f006b002615c8bf0a70f779dfc8f4354a9d64e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 25 Nov 2020 23:51:49 -0800 Subject: [PATCH] pf2: implement open/close disk --- .../vapours/prfile2/pdm/prfile2_pdm_api.hpp | 3 + .../prfile2/pdm/prfile2_pdm_common.hpp | 17 ++- .../vapours/prfile2/pdm/prfile2_pdm_disk.hpp | 26 +++- .../vapours/prfile2/prfile2_handle.hpp | 15 ++ .../source/prfile2/pdm/prfile2_pdm_api.cpp | 23 +++ .../source/prfile2/pdm/prfile2_pdm_disk.cpp | 142 ++++++++++++++++++ .../prfile2/pdm/prfile2_pdm_disk_set.hpp | 8 +- 7 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp diff --git a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_api.hpp b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_api.hpp index 9ebd0c3dc..66a56caab 100644 --- a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_api.hpp +++ b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_api.hpp @@ -22,4 +22,7 @@ namespace ams::prfile2::pdm { pdm::Error Initialize(u32 config, void *param); + pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out); + pdm::Error CloseDisk(HandleType handle); + } diff --git a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_common.hpp b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_common.hpp index 9a0b86b4a..0b17183cb 100644 --- a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_common.hpp +++ b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_common.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include #include namespace ams::prfile2::pdm { @@ -41,14 +42,14 @@ namespace ams::prfile2::pdm { }; struct FunctionTable { - pdm::Error (*initialize)(Disk *); - pdm::Error (*finalize)(Disk *); - pdm::Error (*mount)(Disk *); - pdm::Error (*unmount)(Disk *); - pdm::Error (*format)(Disk *, const u8 *); - pdm::Error (*physical_read)(Disk *disk, u8 *dst, u32 block, u32 count, u32 *num_read); - pdm::Error (*physical_write)(Disk *disk, const u8 *src, u32 block, u32 count, u32 *num_read); - pdm::Error (*get_disk_info)(Disk *disk, DiskInfo *out); + pdm::Error (*initialize)(HandleType disk_handle); + pdm::Error (*finalize)(HandleType disk_handle); + pdm::Error (*mount)(HandleType disk_handle); + pdm::Error (*unmount)(HandleType disk_handle); + pdm::Error (*format)(HandleType disk_handle, const u8 *); + pdm::Error (*physical_read)(HandleType disk_handle, u8 *dst, u32 block, u32 count, u32 *num_read); + pdm::Error (*physical_write)(HandleType disk_handle, const u8 *src, u32 block, u32 count, u32 *num_read); + pdm::Error (*get_disk_info)(HandleType disk_handle, DiskInfo *out); }; struct DiskTable { diff --git a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp index bed18f2d9..c4c212f3b 100644 --- a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp +++ b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp @@ -34,12 +34,34 @@ namespace ams::prfile2::pdm { volatile NonBlockingProtocolType nbc; volatile NonBlockingProtocolType nbc_detect; volatile NonBlockingProtocolType nbc_req; + + template + constexpr ALWAYS_INLINE bool GetStatusBit() const { + constexpr u32 Mask = (1u << Ix); + return (this->status & Mask) != 0; + } + + template + constexpr ALWAYS_INLINE void SetStatusBit(bool en) { + constexpr u32 Mask = (1u << Ix); + if (en) { + this->status |= Mask; + } else { + this->status &= ~Mask; + } + } + + constexpr bool IsOpen() const { return this->GetStatusBit<0>(); } + constexpr void SetOpen(bool en) { this->SetStatusBit<0>(en); } + + constexpr bool IsLocked() const { return this->GetStatusBit<1>(); } + constexpr void SetLocked(bool en) { this->SetStatusBit<1>(en); } }; namespace disk { - pdm::Error OpenDisk(InitDisk *init_disk_table, Disk **out); - pdm::Error CloseDisk(Disk *disk); + pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out); + pdm::Error CloseDisk(HandleType handle); /* ... */ diff --git a/libraries/libvapours/include/vapours/prfile2/prfile2_handle.hpp b/libraries/libvapours/include/vapours/prfile2/prfile2_handle.hpp index fd92e7c58..f2c67fba4 100644 --- a/libraries/libvapours/include/vapours/prfile2/prfile2_handle.hpp +++ b/libraries/libvapours/include/vapours/prfile2/prfile2_handle.hpp @@ -40,6 +40,21 @@ namespace ams::prfile2 { return val; }; + constexpr ALWAYS_INLINE u8 GetHandleId(HandleType handle) { + return handle.Get(); + } + + constexpr ALWAYS_INLINE u16 GetHandleSignature(HandleType handle) { + return handle.Get(); + } + + constexpr inline const HandleType InvalidHandle = {}; + + constexpr ALWAYS_INLINE bool IsInvalidHandle(HandleType handle) { + return handle.value == 0; + } + static_assert(IsInvalidHandle(InvalidHandle)); + constexpr ALWAYS_INLINE HandleType ConstructDiskHandle(u8 id, u16 signature) { return ConstructHandle(id, HandleKind_Disk, signature); } constexpr ALWAYS_INLINE HandleType ConstructPartitionHandle(u8 id, u16 signature) { return ConstructHandle(id, HandleKind_Partition, signature); } diff --git a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_api.cpp b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_api.cpp index 8c9bdae32..fc3859086 100644 --- a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_api.cpp +++ b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_api.cpp @@ -41,4 +41,27 @@ namespace ams::prfile2::pdm { return pdm::Error_Ok; } + pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out) { + /* Check the arguments. */ + if (out == nullptr) { + return pdm::Error_InvalidParameter; + } + + /* Set the output as invalid. */ + *out = InvalidHandle; + + /* Open the disk. */ + return disk::OpenDisk(init_disk_table, out); + } + + pdm::Error CloseDisk(HandleType handle) { + /* Check the input. */ + if (IsInvalidHandle(handle)) { + return pdm::Error_InvalidParameter; + } + + /* Close the disk. */ + return disk::CloseDisk(handle); + } + } diff --git a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp new file mode 100644 index 000000000..ffbfa3578 --- /dev/null +++ b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp @@ -0,0 +1,142 @@ +/* + * 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 . + */ +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include +#elif defined(ATMOSPHERE_IS_MESOSPHERE) +#include +#elif defined(ATMOSPHERE_IS_EXOSPHERE) +#include +#else +#include +#endif +#include "prfile2_pdm_disk_set.hpp" + +namespace ams::prfile2::pdm::disk { + + pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out) { + /* Check the arguments. */ + if (out == nullptr || init_disk_table == nullptr || init_disk_table->function == nullptr) { + return pdm::Error_InvalidParameter; + } + + /* Find a free disk holder. */ + DiskHolder *holder = nullptr; + for (auto &h : impl::g_disk_set.disk_holders) { + if (h.disk == nullptr) { + holder = std::addressof(h); + break; + } + } + if (holder == nullptr) { + return pdm::Error_NotExistFreeDiskStruct; + } + + /* Find a free disk. */ + Disk *disk = nullptr; + for (auto &d : impl::g_disk_set.disks) { + if (!d.IsOpen()) { + disk = std::addressof(d); + break; + } + } + if (disk == nullptr) { + return pdm::Error_NotExistFreeDiskStruct; + } + const auto disk_id = disk - impl::g_disk_set.disks; + + /* Call the disk initialze function. */ + init_disk_table->function(std::addressof(disk->disk_table), init_disk_table->ui_ext); + + /* Set the disk as open .*/ + disk->SetOpen(true); + + /* Set the init disk table. */ + disk->init_disk_table = init_disk_table; + + /* Note the opened disk. */ + ++impl::g_disk_set.num_allocated_disks; + + /* Increment the disk's signature. */ + disk->signature = static_cast(disk->signature + 1); + + /* Increment the disk's open count. */ + ++disk->open_count; + + /* Set the disk in the holder. */ + holder->signature = disk->signature; + holder->disk = disk; + + /* Set the output handle. */ + *out = ConstructDiskHandle(disk_id, disk->signature); + + /* If this was the first opening for the disk, initialize it. */ + if (disk->open_count == 1) { + if (auto err = disk->disk_table.function_table->initialize(*out); err != pdm::Error_Ok) { + /* Close the disk. */ + --disk->open_count; + disk->SetOpen(false); + --impl::g_disk_set.num_allocated_disks; + + /* Reset the holder. */ + holder->disk = nullptr; + + return pdm::Error_DriverError; + } + } + + return pdm::Error_Ok; + } + + pdm::Error CloseDisk(HandleType handle) { + /* Get the disk. */ + Disk *disk = GetDisk(handle); + if (disk == nullptr) { + return pdm::Error_InvalidParameter; + } + + /* Check that the disk is open and unlocked. */ + if (!disk->IsOpen()) { + return pdm::Error_StateClosed; + } + if (disk->IsLocked()) { + return pdm::Error_StateLocked; + } + + /* Close the disk. */ + if (disk->open_count == 1) { + /* Finalize the disk. */ + if (auto err = disk->disk_table.function_table->finalize(handle); err != pdm::Error_Ok) { + if (auto *part = disk->current_partition; part != nullptr) { + /* TODO: part::SetDriverErrorCode(part, err); */ + } + return pdm::Error_DriverError; + } + + /* Set the disk as closed. */ + disk->SetOpen(false); + --impl::g_disk_set.num_allocated_disks; + + /* Clear the disk holder. */ + impl::g_disk_set.disk_holders[GetHandleId(handle)].disk = nullptr; + } + + /* Decrement the disk's open count. */ + --disk->open_count; + + return pdm::Error_Ok; + } + +} diff --git a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp index 7c1f6eab3..2b4c08922 100644 --- a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp +++ b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp @@ -26,8 +26,8 @@ namespace ams::prfile2::pdm { ALWAYS_INLINE Disk *GetDisk(HandleType handle) { if (AMS_LIKELY(IsDiskHandle(handle))) { - if (const auto id = handle.Get(); AMS_LIKELY(id < MaxDisks)) { - const auto signature = handle.Get(); + if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxDisks)) { + const auto signature = GetHandleSignature(handle); Disk *disk = std::addressof(impl::g_disk_set.disks[id]); for (const auto &holder : impl::g_disk_set.disk_holders) { @@ -43,8 +43,8 @@ namespace ams::prfile2::pdm { ALWAYS_INLINE Partition *GetPartition(HandleType handle) { if (AMS_LIKELY(IsPartitionHandle(handle))) { - if (const auto id = handle.Get(); AMS_LIKELY(id < MaxPartitions)) { - const auto signature = handle.Get(); + if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxPartitions)) { + const auto signature = GetHandleSignature(handle); Partition *part = std::addressof(impl::g_disk_set.partitions[id]); for (const auto &holder : impl::g_disk_set.partition_holders) {