⛏️ index : haiku.git

/*
 * Copyright 2020-2021, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *   X512 <danger_mail@list.ru>
 */
#ifndef _RISCV64VMTRANSLATIONMAP_H_
#define _RISCV64VMTRANSLATIONMAP_H_


#include <atomic>

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


enum {
	PAGE_INVALIDATE_CACHE_SIZE = 64
};


struct RISCV64VMTranslationMap: public VMTranslationMap {
								RISCV64VMTranslationMap(bool kernel,
									phys_addr_t pageTable = 0);
	virtual						~RISCV64VMTranslationMap();

	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);

			void				SetFlags(addr_t virtualAddress,
									uint32 flags);

	virtual	status_t			ClearFlags(addr_t virtualAddress,
									uint32 flags);

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

	virtual	void				Flush();

	virtual	void				DebugPrintMappingInfo(addr_t virtualAddress);
	virtual	bool				DebugGetReverseMappingInfo(
									phys_addr_t physicalAddress,
									ReverseMappingInfoCallback& callback);

	inline	phys_addr_t			PageTable();
	inline	uint64				Satp();

			status_t			MemcpyToMap(addr_t to, const char *from,
									size_t size);
			status_t			MemcpyFromMap(char *to, addr_t from,
									size_t size);
			status_t			MemsetToMap(addr_t to, char c, size_t count);
			ssize_t				StrlcpyFromMap(char *to, addr_t from,
									size_t size);
			ssize_t				StrlcpyToMap(addr_t to, const char *from,
									size_t size);

	inline	CPUSet&				ActiveOnCpus();
	inline	void				InvalidatePage(addr_t address);

private:
			std::atomic<Pte>*	LookupPte(addr_t virtAdr, bool alloc,
									vm_page_reservation* reservation);
			phys_addr_t			LookupAddr(addr_t virtAdr);

			bool				fIsKernel;
			phys_addr_t			fPageTable;
			uint64				fPageTableSize; // in page units
			CPUSet				fActiveOnCpus;
			int					fInvalidPagesCount;
			addr_t				fInvalidPages[PAGE_INVALIDATE_CACHE_SIZE];
			bool				fInvalidCode;
};


inline phys_addr_t
RISCV64VMTranslationMap::PageTable()
{
	return fPageTable;
}


inline uint64
RISCV64VMTranslationMap::Satp()
{
	SatpReg satp;
	satp.ppn = fPageTable / B_PAGE_SIZE;
	satp.asid = 0;
	satp.mode = satpModeSv39;
	return satp.val;
}


CPUSet&
RISCV64VMTranslationMap::ActiveOnCpus()
{
	return fActiveOnCpus;
}


void
RISCV64VMTranslationMap::InvalidatePage(addr_t address)
{
	if (fInvalidPagesCount < PAGE_INVALIDATE_CACHE_SIZE)
		fInvalidPages[fInvalidPagesCount] = address;

	fInvalidPagesCount++;
}


struct RISCV64VMPhysicalPageMapper: public VMPhysicalPageMapper {
								RISCV64VMPhysicalPageMapper();
	virtual						~RISCV64VMPhysicalPageMapper();

	virtual	status_t			GetPage(phys_addr_t physicalAddress,
									addr_t* _virtualAddress,
									void** _handle);
	virtual	status_t			PutPage(addr_t virtualAddress,
									void* handle);

	virtual	status_t			GetPageCurrentCPU(
									phys_addr_t physicalAddress,
									addr_t* _virtualAddress,
									void** _handle);
	virtual	status_t			PutPageCurrentCPU(addr_t virtualAddress,
									void* _handle);

	virtual	status_t			GetPageDebug(phys_addr_t physicalAddress,
									addr_t* _virtualAddress,
									void** _handle);
	virtual	status_t			PutPageDebug(addr_t virtualAddress,
									void* handle);

	virtual	status_t			MemsetPhysical(phys_addr_t address, int value,
									phys_size_t length);
	virtual	status_t			MemcpyFromPhysical(void* to, phys_addr_t from,
									size_t length, bool user);
	virtual	status_t			MemcpyToPhysical(phys_addr_t to,
									const void* from, size_t length,
									bool user);
	virtual	void				MemcpyPhysicalPage(phys_addr_t to,
									phys_addr_t from);
};


#endif	// _RISCV64VMTRANSLATIONMAP_H_