root/src/system/kernel/arch/arm64/VMSAv8TranslationMap.h
/*
 * Copyright 2022 Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 */
#ifndef VMSA_V8_TRANSLATION_MAP_H
#define VMSA_V8_TRANSLATION_MAP_H


#include <arch_cpu_defs.h>
#include <vm/VMTranslationMap.h>


static constexpr uint64_t kPteAddrMask = (((1UL << 36) - 1) << 12);
static constexpr uint64_t kPteAttrMask = ~(kPteAddrMask | 0x3);
static constexpr uint64_t kPteTLBCompatMask = (kPteAddrMask | (0x3 << 2) | (0x3 << 8));

static constexpr uint64_t kPteValidMask = 0x1;
static constexpr uint64_t kPteTypeMask = 0x3;
static constexpr uint64_t kPteTypeL012Table = 0x3;
static constexpr uint64_t kPteTypeL12Block = 0x1;
static constexpr uint64_t kPteTypeL3Page = 0x3;

static constexpr uint64_t kAttrSWDIRTY = (1UL << 56);
static constexpr uint64_t kAttrSWDBM = (1UL << 55);
static constexpr uint64_t kAttrUXN = (1UL << 54);
static constexpr uint64_t kAttrPXN = (1UL << 53);
static constexpr uint64_t kAttrDBM = (1UL << 51);
static constexpr uint64_t kAttrNG = (1UL << 11);
static constexpr uint64_t kAttrAF = (1UL << 10);
static constexpr uint64_t kAttrShareability = (3UL << 8);
static constexpr uint64_t kAttrSHInnerShareable = (3UL << 8);
static constexpr uint64_t kAttrAPReadOnly = (1UL << 7);
static constexpr uint64_t kAttrAPUserAccess = (1UL << 6);
static constexpr uint64_t kAttrMemoryAttrIdx = (3UL << 2);

static constexpr uint64_t kTLBIMask = ((1UL << 44) - 1);
static constexpr uint64_t kASIDMask = 0xFF00000000000000UL;


struct VMSAv8TranslationMap : public VMTranslationMap {
public:
        VMSAv8TranslationMap(
                bool kernel, phys_addr_t pageTable, int pageBits, int vaBits, int minBlockLevel);
        ~VMSAv8TranslationMap();

        virtual bool                            Lock();
        virtual void                            Unlock();

        virtual addr_t                          MappedSize() const;
        virtual size_t                          MaxPagesNeededToMap(addr_t start,
                                                                        addr_t end) const;

        virtual status_t                        Map(addr_t virtualAddress,
                                                                        phys_addr_t physicalAddress,
                                                                        uint32 attributes, uint32 memoryType,
                                                                        vm_page_reservation* reservation);
        virtual status_t                        Unmap(addr_t start, addr_t end);

        virtual status_t                        UnmapPage(VMArea* area, addr_t address,
                                                                        bool updatePageQueue,
                                                                        bool deletingAddressSpace, uint32* _flags);
        virtual void                            UnmapPages(VMArea* area, addr_t base,
                                                                        size_t size, bool updatePageQueue,
                                                                        bool deletingAddressSpace);

        virtual status_t                        Query(addr_t virtualAddress,
                                                                        phys_addr_t* _physicalAddress,
                                                                        uint32* _flags);
        virtual status_t                        QueryInterrupt(addr_t virtualAddress,
                                                                        phys_addr_t* _physicalAddress,
                                                                        uint32* _flags);

        virtual status_t                        Protect(addr_t base, addr_t top,
                                                                        uint32 attributes, uint32 memoryType);

        virtual status_t                        ClearFlags(addr_t virtualAddress,
                                                                        uint32 flags);

        virtual bool                            ClearAccessedAndModified(
                                                                        VMArea* area, addr_t address,
                                                                        bool unmapIfUnaccessed,
                                                                        bool& _modified);

        virtual void                            Flush();

        enum HWFeature {
                // Can HW update Access and Dirty flags, respectively?
                HW_ACCESS = 0x1,
                HW_DIRTY = 0x2,

                // Can we use the CNP bit to indicate that ASIDs are consistent across cores?
                HW_COMMON_NOT_PRIVATE = 0x4
        };

        static uint32_t fHwFeature;
        static uint64_t fMair;

        static uint64_t GetMemoryAttr(uint32 attributes, uint32 memoryType, bool isKernel);
        static int CalcStartLevel(int vaBits, int pageBits);

        static void SwitchUserMap(VMSAv8TranslationMap *from, VMSAv8TranslationMap *to);

private:
        bool fIsKernel;
        phys_addr_t fPageTable;
        int fPageBits;
        int fVaBits;
        int fMinBlockLevel;
        int fInitialLevel;
        int fASID;
        int fRefcount;

private:
        static uint8_t MairIndex(uint8_t type);
        bool ValidateVa(addr_t va);
        uint64_t* TableFromPa(phys_addr_t pa);
        void FreeTable(phys_addr_t ptPa, uint64_t va, int level, vm_page_reservation* reservation);
        phys_addr_t GetOrMakeTable(phys_addr_t ptPa, int level, int index, vm_page_reservation* reservation);
        template<typename UpdatePte>
        void ProcessRange(phys_addr_t ptPa, int level, addr_t va, size_t size,
                vm_page_reservation* reservation, UpdatePte &&updatePte);
        bool AttemptPteBreakBeforeMake(uint64_t* ptePtr, uint64_t oldPte, addr_t va);
        bool FlushVAIfAccessed(uint64_t pte, addr_t va);
};


#endif