namespace os {
+/** \brief A class that handles the translation from physical to virtual addresses.
+ *
+ * It avoids the risk of translating an address zero or two times, by storing
+ * physical addresses as a different class.
+ */
template <typename T>
class phys_ptr {
public:
+ /** Constructs a phys_ptr corresponding to the given physical address.
+ */
constexpr explicit phys_ptr(std::uintptr_t phys_addr): phys_addr(phys_addr) {}
+ /** Constructs a phys_ptr that doesn't correspond to any place in physical memory.
+ * It is represented internally by ~0 instead of 0 to allow for access of physical address 0.
+ */
constexpr phys_ptr(std::nullptr_t): phys_addr(~0ull) {}
+ /** Access the T at the physical address of the ith element of a T array starting at this physical address.
+ */
T& operator[](std::size_t i) const {
return get_virt_addr()[i];
}
+ /** Access the T at this physical address.
+ */
T& operator*() const {
return *get_virt_addr();
}
+ /** Access the T at this physical address.
+ */
T* operator->() const {
return get_virt_addr();
}
+ /** Change the address to that of the following T in physical memory.
+ * \return New address.
+ */
constexpr phys_ptr<T>& operator++() {
return *this += 1;
}
+ /** Change the address to that of the following T in physical memory.
+ * \return Old address.
+ */
constexpr phys_ptr<T> operator++(int) {
const auto old = *this;
operator++();
return old;
}
+ /** Change the address to that of the previous T in physical memory.
+ * \return New address.
+ */
constexpr phys_ptr<T>& operator--() {
return *this -= 1;
}
+ /** Change the address to that of the previous T in physical memory.
+ * \return Old address.
+ */
constexpr phys_ptr<T> operator--(int) {
const auto old = *this;
operator--();
return old;
}
+ /** Move offset Ts forwards in physical memory.
+ * \return New address.
+ */
constexpr phys_ptr<T>& operator+=(std::ptrdiff_t offset) {
return *this = *this + offset;
}
+ /** Move offset Ts backwards in physical memory.
+ * \return New address.
+ */
constexpr phys_ptr<T>& operator-=(std::ptrdiff_t offset) {
return *this = *this - offset;
}
+ /** \return A new phys_ptr refering to the T offset Ts forward from ptr.
+ */
friend constexpr phys_ptr<T> operator+(phys_ptr<T> ptr, std::ptrdiff_t offset) {
return phys_ptr<T>{ptr.phys_addr + offset * sizeof(T)};
}
+ /** \return A new phys_ptr refering to the T offset Ts forward from ptr.
+ */
friend constexpr phys_ptr<T> operator+(std::ptrdiff_t offset, phys_ptr<T> ptr) {
return ptr + offset;
}
+ /** \return A new phys_ptr refering to the T offset Ts backwards from ptr.
+ */
friend constexpr phys_ptr<T> operator-(phys_ptr<T> ptr, std::ptrdiff_t offset) {
return phys_ptr<T>{ptr.phys_addr - offset * sizeof(T)};
}
+ /** \return The numbers of Ts between the two phys_ptr.
+ */
friend constexpr std::ptrdiff_t operator-(phys_ptr<T> a, phys_ptr<T> b) {
return (a.phys_addr - b.phys_addr) / sizeof(T);
}
+ /** \return This physical address, as a uintptr_t.
+ */
constexpr std::uintptr_t get_phys_addr() const {
return phys_addr;
}
+ /** Compare the physical addresses, an address that's before another one in memory is smaller than that one.
+ */
friend constexpr auto operator<=>(phys_ptr<T> a, phys_ptr<T> b) = default;
private:
+ /** The function used inside of the class to get the virtual address that corresponds to this physical address.
+ */
constexpr T* get_virt_addr() const {
return reinterpret_cast<T*>(phys_addr + 0xFFFF800000000000);
}
+ /** This physical address, as a std::uintptr_t
+ */
std::uintptr_t phys_addr;
};