kvm_mmu.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
  4. */
  5. #ifndef __ASM_LOONGARCH_KVM_MMU_H__
  6. #define __ASM_LOONGARCH_KVM_MMU_H__
  7. #include <linux/kvm_host.h>
  8. #include <asm/pgalloc.h>
  9. #include <asm/tlb.h>
  10. /*
  11. * KVM_MMU_CACHE_MIN_PAGES is the number of GPA page table translation levels
  12. * for which pages need to be cached.
  13. */
  14. #define KVM_MMU_CACHE_MIN_PAGES (CONFIG_PGTABLE_LEVELS - 1)
  15. /*
  16. * _PAGE_MODIFIED is a SW pte bit, it records page ever written on host
  17. * kernel, on secondary MMU it records the page writeable attribute, in
  18. * order for fast path handling.
  19. */
  20. #define KVM_PAGE_WRITEABLE _PAGE_MODIFIED
  21. #define _KVM_FLUSH_PGTABLE 0x1
  22. #define _KVM_HAS_PGMASK 0x2
  23. #define kvm_pfn_pte(pfn, prot) (((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot))
  24. #define kvm_pte_pfn(x) ((phys_addr_t)((x & _PFN_MASK) >> PFN_PTE_SHIFT))
  25. typedef unsigned long kvm_pte_t;
  26. typedef struct kvm_ptw_ctx kvm_ptw_ctx;
  27. typedef int (*kvm_pte_ops)(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx);
  28. struct kvm_ptw_ctx {
  29. kvm_pte_ops ops;
  30. unsigned long flag;
  31. /* for kvm_arch_mmu_enable_log_dirty_pt_masked use */
  32. unsigned long mask;
  33. unsigned long gfn;
  34. /* page walk mmu info */
  35. unsigned int level;
  36. unsigned long pgtable_shift;
  37. unsigned long invalid_entry;
  38. unsigned long *invalid_ptes;
  39. unsigned int *pte_shifts;
  40. void *opaque;
  41. /* free pte table page list */
  42. struct list_head list;
  43. };
  44. kvm_pte_t *kvm_pgd_alloc(void);
  45. static inline void kvm_set_pte(kvm_pte_t *ptep, kvm_pte_t val)
  46. {
  47. WRITE_ONCE(*ptep, val);
  48. }
  49. static inline int kvm_pte_young(kvm_pte_t pte) { return pte & _PAGE_ACCESSED; }
  50. static inline int kvm_pte_huge(kvm_pte_t pte) { return pte & _PAGE_HUGE; }
  51. static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & __WRITEABLE; }
  52. static inline int kvm_pte_writeable(kvm_pte_t pte) { return pte & KVM_PAGE_WRITEABLE; }
  53. static inline kvm_pte_t kvm_pte_mkyoung(kvm_pte_t pte)
  54. {
  55. return pte | _PAGE_ACCESSED;
  56. }
  57. static inline kvm_pte_t kvm_pte_mkold(kvm_pte_t pte)
  58. {
  59. return pte & ~_PAGE_ACCESSED;
  60. }
  61. static inline kvm_pte_t kvm_pte_mkdirty(kvm_pte_t pte)
  62. {
  63. return pte | __WRITEABLE;
  64. }
  65. static inline kvm_pte_t kvm_pte_mkclean(kvm_pte_t pte)
  66. {
  67. return pte & ~__WRITEABLE;
  68. }
  69. static inline kvm_pte_t kvm_pte_mkhuge(kvm_pte_t pte)
  70. {
  71. return pte | _PAGE_HUGE;
  72. }
  73. static inline kvm_pte_t kvm_pte_mksmall(kvm_pte_t pte)
  74. {
  75. return pte & ~_PAGE_HUGE;
  76. }
  77. static inline kvm_pte_t kvm_pte_mkwriteable(kvm_pte_t pte)
  78. {
  79. return pte | KVM_PAGE_WRITEABLE;
  80. }
  81. static inline int kvm_need_flush(kvm_ptw_ctx *ctx)
  82. {
  83. return ctx->flag & _KVM_FLUSH_PGTABLE;
  84. }
  85. static inline kvm_pte_t *kvm_pgtable_offset(kvm_ptw_ctx *ctx, kvm_pte_t *table,
  86. phys_addr_t addr)
  87. {
  88. return table + ((addr >> ctx->pgtable_shift) & (PTRS_PER_PTE - 1));
  89. }
  90. static inline phys_addr_t kvm_pgtable_addr_end(kvm_ptw_ctx *ctx,
  91. phys_addr_t addr, phys_addr_t end)
  92. {
  93. phys_addr_t boundary, size;
  94. size = 0x1UL << ctx->pgtable_shift;
  95. boundary = (addr + size) & ~(size - 1);
  96. return (boundary - 1 < end - 1) ? boundary : end;
  97. }
  98. static inline int kvm_pte_present(kvm_ptw_ctx *ctx, kvm_pte_t *entry)
  99. {
  100. if (!ctx || ctx->level == 0)
  101. return !!(*entry & _PAGE_PRESENT);
  102. return *entry != ctx->invalid_entry;
  103. }
  104. static inline int kvm_pte_none(kvm_ptw_ctx *ctx, kvm_pte_t *entry)
  105. {
  106. return *entry == ctx->invalid_entry;
  107. }
  108. static inline void kvm_ptw_enter(kvm_ptw_ctx *ctx)
  109. {
  110. ctx->level--;
  111. ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
  112. ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
  113. }
  114. static inline void kvm_ptw_exit(kvm_ptw_ctx *ctx)
  115. {
  116. ctx->level++;
  117. ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
  118. ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
  119. }
  120. #endif /* __ASM_LOONGARCH_KVM_MMU_H__ */