/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _PAGE_IDLE_H #define _PAGE_IDLE_H #include #define SCAN_HUGE_PAGE O_NONBLOCK /* only huge page */ #define SCAN_SKIM_IDLE O_NOFOLLOW /* stop on PMD_IDLE_PTES */ #define SCAN_DIRTY_PAGE O_NOATIME /* report pte/pmd dirty bit */ /* define to not used file flags */ #define SCAN_AS_HUGE 0100000000 /* treat normal page as hugepage in vm */ #define SCAN_IGN_HOST 0200000000 /* ignore host access when scan vm */ #define VM_SCAN_HOST 0400000000 /* scan and add host page for vm hole(internal) */ #define ALL_SCAN_FLAGS (SCAN_HUGE_PAGE | SCAN_SKIM_IDLE | SCAN_DIRTY_PAGE | \ SCAN_AS_HUGE | SCAN_IGN_HOST | VM_SCAN_HOST) #define IDLE_SCAN_MAGIC 0x66 #define IDLE_SCAN_ADD_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x0, unsigned int) #define IDLE_SCAN_REMOVE_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x1, unsigned int) enum ProcIdlePageType { PTE_ACCESSED, /* 4k page */ PMD_ACCESSED, /* 2M page */ PUD_PRESENT, /* 1G page */ PTE_DIRTY_M, PMD_DIRTY_M, PTE_IDLE, PMD_IDLE, PMD_IDLE_PTES, /* all PTE idle */ PTE_HOLE, PMD_HOLE, PIP_CMD, IDLE_PAGE_TYPE_MAX }; #define PIP_TYPE(a) (0xf & (a >> 4)) #define PIP_SIZE(a) (0xf & a) #define PIP_COMPOSE(type, nr) ((type << 4) | nr) #define PIP_CMD_SET_HVA PIP_COMPOSE(PIP_CMD, 0) #ifndef INVALID_PAGE #define INVALID_PAGE ~0UL #endif #ifdef CONFIG_ARM64 #define _PAGE_MM_BIT_ACCESSED 10 #else #define _PAGE_MM_BIT_ACCESSED _PAGE_BIT_ACCESSED #endif #ifdef CONFIG_X86_64 #define _PAGE_BIT_EPT_ACCESSED 8 #define _PAGE_BIT_EPT_DIRTY 9 #define _PAGE_EPT_ACCESSED (_AT(pteval_t, 1) << _PAGE_BIT_EPT_ACCESSED) #define _PAGE_EPT_DIRTY (_AT(pteval_t, 1) << _PAGE_BIT_EPT_DIRTY) #define _PAGE_EPT_PRESENT (_AT(pteval_t, 7)) static inline int ept_pte_present(pte_t a) { return pte_flags(a) & _PAGE_EPT_PRESENT; } static inline int ept_pmd_present(pmd_t a) { return pmd_flags(a) & _PAGE_EPT_PRESENT; } static inline int ept_pud_present(pud_t a) { return pud_flags(a) & _PAGE_EPT_PRESENT; } static inline int ept_p4d_present(p4d_t a) { return p4d_flags(a) & _PAGE_EPT_PRESENT; } static inline int ept_pgd_present(pgd_t a) { return pgd_flags(a) & _PAGE_EPT_PRESENT; } static inline int ept_pte_accessed(pte_t a) { return pte_flags(a) & _PAGE_EPT_ACCESSED; } static inline int ept_pmd_accessed(pmd_t a) { return pmd_flags(a) & _PAGE_EPT_ACCESSED; } static inline int ept_pud_accessed(pud_t a) { return pud_flags(a) & _PAGE_EPT_ACCESSED; } static inline int ept_p4d_accessed(p4d_t a) { return p4d_flags(a) & _PAGE_EPT_ACCESSED; } static inline int ept_pgd_accessed(pgd_t a) { return pgd_flags(a) & _PAGE_EPT_ACCESSED; } #endif extern struct file_operations proc_page_scan_operations; #define PAGE_IDLE_KBUF_FULL 1 #define PAGE_IDLE_BUF_FULL 2 #define PAGE_IDLE_BUF_MIN (sizeof(uint64_t) * 2 + 3) #define PAGE_IDLE_KBUF_SIZE 8000 struct page_idle_ctrl { struct mm_struct *mm; struct kvm *kvm; uint8_t kpie[PAGE_IDLE_KBUF_SIZE]; int pie_read; int pie_read_max; void __user *buf; int buf_size; int bytes_copied; unsigned long next_hva; /* GPA for EPT; VA for PT */ unsigned long gpa_to_hva; unsigned long restart_gpa; unsigned long last_va; unsigned int flags; }; #endif