|
@@ -104,6 +104,39 @@ static inline int is_present_gpte(unsigned long pte)
|
|
|
return pte & PT_PRESENT_MASK;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Currently, we have two sorts of write-protection, a) the first one
|
|
|
+ * write-protects guest page to sync the guest modification, b) another one is
|
|
|
+ * used to sync dirty bitmap when we do KVM_GET_DIRTY_LOG. The differences
|
|
|
+ * between these two sorts are:
|
|
|
+ * 1) the first case clears SPTE_MMU_WRITEABLE bit.
|
|
|
+ * 2) the first case requires flushing tlb immediately avoiding corrupting
|
|
|
+ * shadow page table between all vcpus so it should be in the protection of
|
|
|
+ * mmu-lock. And the another case does not need to flush tlb until returning
|
|
|
+ * the dirty bitmap to userspace since it only write-protects the page
|
|
|
+ * logged in the bitmap, that means the page in the dirty bitmap is not
|
|
|
+ * missed, so it can flush tlb out of mmu-lock.
|
|
|
+ *
|
|
|
+ * So, there is the problem: the first case can meet the corrupted tlb caused
|
|
|
+ * by another case which write-protects pages but without flush tlb
|
|
|
+ * immediately. In order to making the first case be aware this problem we let
|
|
|
+ * it flush tlb if we try to write-protect a spte whose SPTE_MMU_WRITEABLE bit
|
|
|
+ * is set, it works since another case never touches SPTE_MMU_WRITEABLE bit.
|
|
|
+ *
|
|
|
+ * Anyway, whenever a spte is updated (only permission and status bits are
|
|
|
+ * changed) we need to check whether the spte with SPTE_MMU_WRITEABLE becomes
|
|
|
+ * readonly, if that happens, we need to flush tlb. Fortunately,
|
|
|
+ * mmu_spte_update() has already handled it perfectly.
|
|
|
+ *
|
|
|
+ * The rules to use SPTE_MMU_WRITEABLE and PT_WRITABLE_MASK:
|
|
|
+ * - if we want to see if it has writable tlb entry or if the spte can be
|
|
|
+ * writable on the mmu mapping, check SPTE_MMU_WRITEABLE, this is the most
|
|
|
+ * case, otherwise
|
|
|
+ * - if we fix page fault on the spte or do write-protection by dirty logging,
|
|
|
+ * check PT_WRITABLE_MASK.
|
|
|
+ *
|
|
|
+ * TODO: introduce APIs to split these two cases.
|
|
|
+ */
|
|
|
static inline int is_writable_pte(unsigned long pte)
|
|
|
{
|
|
|
return pte & PT_WRITABLE_MASK;
|