⛏️ index : haiku.git

/*
 * 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