diff options
| author | Avi Kivity <avi@qumranet.com> | 2007-12-09 09:15:46 -0500 |
|---|---|---|
| committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:53:20 -0500 |
| commit | fe135d2ceb3d7dc08151b3cbad96565d02cc8676 (patch) | |
| tree | 7dec07ec0a32a53f003551802cb73c4ce3373527 /drivers/kvm | |
| parent | b3e4e63fd9ee8cd5d9047b89e0d463d5c48ee5b5 (diff) | |
KVM: MMU: Simplify calculation of pte access
The nx bit is awkwardly placed in the 63rd bit position; furthermore it
has a reversed meaning compared to the other bits, which means we can't use
a bitwise and to calculate compounded access masks.
So, we simplify things by creating a new 3-bit exec/write/user access word,
and doing all calculations in that.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm')
| -rw-r--r-- | drivers/kvm/mmu.c | 14 | ||||
| -rw-r--r-- | drivers/kvm/paging_tmpl.h | 58 |
2 files changed, 43 insertions, 29 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 62a74151f847..f8a2137c64a2 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c | |||
| @@ -85,7 +85,8 @@ static int dbg = 1; | |||
| 85 | #define PT_PAGE_SIZE_MASK (1ULL << 7) | 85 | #define PT_PAGE_SIZE_MASK (1ULL << 7) |
| 86 | #define PT_PAT_MASK (1ULL << 7) | 86 | #define PT_PAT_MASK (1ULL << 7) |
| 87 | #define PT_GLOBAL_MASK (1ULL << 8) | 87 | #define PT_GLOBAL_MASK (1ULL << 8) |
| 88 | #define PT64_NX_MASK (1ULL << 63) | 88 | #define PT64_NX_SHIFT 63 |
| 89 | #define PT64_NX_MASK (1ULL << PT64_NX_SHIFT) | ||
| 89 | 90 | ||
| 90 | #define PT_PAT_SHIFT 7 | 91 | #define PT_PAT_SHIFT 7 |
| 91 | #define PT_DIR_PAT_SHIFT 12 | 92 | #define PT_DIR_PAT_SHIFT 12 |
| @@ -153,6 +154,11 @@ static int dbg = 1; | |||
| 153 | 154 | ||
| 154 | #define RMAP_EXT 4 | 155 | #define RMAP_EXT 4 |
| 155 | 156 | ||
| 157 | #define ACC_EXEC_MASK 1 | ||
| 158 | #define ACC_WRITE_MASK PT_WRITABLE_MASK | ||
| 159 | #define ACC_USER_MASK PT_USER_MASK | ||
| 160 | #define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK) | ||
| 161 | |||
| 156 | struct kvm_rmap_desc { | 162 | struct kvm_rmap_desc { |
| 157 | u64 *shadow_ptes[RMAP_EXT]; | 163 | u64 *shadow_ptes[RMAP_EXT]; |
| 158 | struct kvm_rmap_desc *more; | 164 | struct kvm_rmap_desc *more; |
| @@ -921,7 +927,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, struct page *page) | |||
| 921 | >> PAGE_SHIFT; | 927 | >> PAGE_SHIFT; |
| 922 | new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, | 928 | new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, |
| 923 | v, level - 1, | 929 | v, level - 1, |
| 924 | 1, 3, &table[index]); | 930 | 1, ACC_ALL, &table[index]); |
| 925 | if (!new_table) { | 931 | if (!new_table) { |
| 926 | pgprintk("nonpaging_map: ENOMEM\n"); | 932 | pgprintk("nonpaging_map: ENOMEM\n"); |
| 927 | kvm_release_page_clean(page); | 933 | kvm_release_page_clean(page); |
| @@ -988,7 +994,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
| 988 | 994 | ||
| 989 | ASSERT(!VALID_PAGE(root)); | 995 | ASSERT(!VALID_PAGE(root)); |
| 990 | sp = kvm_mmu_get_page(vcpu, root_gfn, 0, | 996 | sp = kvm_mmu_get_page(vcpu, root_gfn, 0, |
| 991 | PT64_ROOT_LEVEL, 0, 0, NULL); | 997 | PT64_ROOT_LEVEL, 0, ACC_ALL, NULL); |
| 992 | root = __pa(sp->spt); | 998 | root = __pa(sp->spt); |
| 993 | ++sp->root_count; | 999 | ++sp->root_count; |
| 994 | vcpu->mmu.root_hpa = root; | 1000 | vcpu->mmu.root_hpa = root; |
| @@ -1009,7 +1015,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
| 1009 | root_gfn = 0; | 1015 | root_gfn = 0; |
| 1010 | sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, | 1016 | sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, |
| 1011 | PT32_ROOT_LEVEL, !is_paging(vcpu), | 1017 | PT32_ROOT_LEVEL, !is_paging(vcpu), |
| 1012 | 0, NULL); | 1018 | ACC_ALL, NULL); |
| 1013 | root = __pa(sp->spt); | 1019 | root = __pa(sp->spt); |
| 1014 | ++sp->root_count; | 1020 | ++sp->root_count; |
| 1015 | vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; | 1021 | vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; |
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 8086f827120f..7688cbf413c8 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h | |||
| @@ -66,7 +66,8 @@ struct guest_walker { | |||
| 66 | int level; | 66 | int level; |
| 67 | gfn_t table_gfn[PT_MAX_FULL_LEVELS]; | 67 | gfn_t table_gfn[PT_MAX_FULL_LEVELS]; |
| 68 | pt_element_t pte; | 68 | pt_element_t pte; |
| 69 | pt_element_t inherited_ar; | 69 | unsigned pt_access; |
| 70 | unsigned pte_access; | ||
| 70 | gfn_t gfn; | 71 | gfn_t gfn; |
| 71 | u32 error_code; | 72 | u32 error_code; |
| 72 | }; | 73 | }; |
| @@ -110,7 +111,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, | |||
| 110 | { | 111 | { |
| 111 | pt_element_t pte; | 112 | pt_element_t pte; |
| 112 | gfn_t table_gfn; | 113 | gfn_t table_gfn; |
| 113 | unsigned index; | 114 | unsigned index, pt_access, pte_access; |
| 114 | gpa_t pte_gpa; | 115 | gpa_t pte_gpa; |
| 115 | 116 | ||
| 116 | pgprintk("%s: addr %lx\n", __FUNCTION__, addr); | 117 | pgprintk("%s: addr %lx\n", __FUNCTION__, addr); |
| @@ -128,7 +129,7 @@ walk: | |||
| 128 | ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || | 129 | ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || |
| 129 | (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); | 130 | (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); |
| 130 | 131 | ||
| 131 | walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; | 132 | pt_access = ACC_ALL; |
| 132 | 133 | ||
| 133 | for (;;) { | 134 | for (;;) { |
| 134 | index = PT_INDEX(addr, walker->level); | 135 | index = PT_INDEX(addr, walker->level); |
| @@ -165,6 +166,14 @@ walk: | |||
| 165 | pte |= PT_ACCESSED_MASK; | 166 | pte |= PT_ACCESSED_MASK; |
| 166 | } | 167 | } |
| 167 | 168 | ||
| 169 | pte_access = pte & (PT_WRITABLE_MASK | PT_USER_MASK); | ||
| 170 | pte_access |= ACC_EXEC_MASK; | ||
| 171 | #if PTTYPE == 64 | ||
| 172 | if (is_nx(vcpu)) | ||
| 173 | pte_access &= ~(pte >> PT64_NX_SHIFT); | ||
| 174 | #endif | ||
| 175 | pte_access &= pt_access; | ||
| 176 | |||
| 168 | if (walker->level == PT_PAGE_TABLE_LEVEL) { | 177 | if (walker->level == PT_PAGE_TABLE_LEVEL) { |
| 169 | walker->gfn = gpte_to_gfn(pte); | 178 | walker->gfn = gpte_to_gfn(pte); |
| 170 | break; | 179 | break; |
| @@ -180,7 +189,7 @@ walk: | |||
| 180 | break; | 189 | break; |
| 181 | } | 190 | } |
| 182 | 191 | ||
| 183 | walker->inherited_ar &= pte; | 192 | pt_access = pte_access; |
| 184 | --walker->level; | 193 | --walker->level; |
| 185 | } | 194 | } |
| 186 | 195 | ||
| @@ -197,7 +206,10 @@ walk: | |||
| 197 | } | 206 | } |
| 198 | 207 | ||
| 199 | walker->pte = pte; | 208 | walker->pte = pte; |
| 200 | pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)pte); | 209 | walker->pt_access = pt_access; |
| 210 | walker->pte_access = pte_access; | ||
| 211 | pgprintk("%s: pte %llx pte_access %x pt_access %x\n", | ||
| 212 | __FUNCTION__, (u64)pte, pt_access, pte_access); | ||
| 201 | return 1; | 213 | return 1; |
| 202 | 214 | ||
| 203 | not_present: | 215 | not_present: |
| @@ -218,7 +230,8 @@ err: | |||
| 218 | } | 230 | } |
| 219 | 231 | ||
| 220 | static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | 232 | static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, |
| 221 | u64 *shadow_pte, u64 access_bits, | 233 | u64 *shadow_pte, unsigned pt_access, |
| 234 | unsigned pte_access, | ||
| 222 | int user_fault, int write_fault, | 235 | int user_fault, int write_fault, |
| 223 | int *ptwrite, struct guest_walker *walker, | 236 | int *ptwrite, struct guest_walker *walker, |
| 224 | gfn_t gfn) | 237 | gfn_t gfn) |
| @@ -228,12 +241,11 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | |||
| 228 | int was_rmapped = is_rmap_pte(*shadow_pte); | 241 | int was_rmapped = is_rmap_pte(*shadow_pte); |
| 229 | struct page *page; | 242 | struct page *page; |
| 230 | 243 | ||
| 231 | pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d" | 244 | pgprintk("%s: spte %llx gpte %llx access %x write_fault %d" |
| 232 | " user_fault %d gfn %lx\n", | 245 | " user_fault %d gfn %lx\n", |
| 233 | __FUNCTION__, *shadow_pte, (u64)gpte, access_bits, | 246 | __FUNCTION__, *shadow_pte, (u64)gpte, pt_access, |
| 234 | write_fault, user_fault, gfn); | 247 | write_fault, user_fault, gfn); |
| 235 | 248 | ||
| 236 | access_bits &= gpte; | ||
| 237 | /* | 249 | /* |
| 238 | * We don't set the accessed bit, since we sometimes want to see | 250 | * We don't set the accessed bit, since we sometimes want to see |
| 239 | * whether the guest actually used the pte (in order to detect | 251 | * whether the guest actually used the pte (in order to detect |
| @@ -242,12 +254,12 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | |||
| 242 | spte = PT_PRESENT_MASK | PT_DIRTY_MASK; | 254 | spte = PT_PRESENT_MASK | PT_DIRTY_MASK; |
| 243 | spte |= gpte & PT64_NX_MASK; | 255 | spte |= gpte & PT64_NX_MASK; |
| 244 | if (!dirty) | 256 | if (!dirty) |
| 245 | access_bits &= ~PT_WRITABLE_MASK; | 257 | pte_access &= ~ACC_WRITE_MASK; |
| 246 | 258 | ||
| 247 | page = gfn_to_page(vcpu->kvm, gfn); | 259 | page = gfn_to_page(vcpu->kvm, gfn); |
| 248 | 260 | ||
| 249 | spte |= PT_PRESENT_MASK; | 261 | spte |= PT_PRESENT_MASK; |
| 250 | if (access_bits & PT_USER_MASK) | 262 | if (pte_access & ACC_USER_MASK) |
| 251 | spte |= PT_USER_MASK; | 263 | spte |= PT_USER_MASK; |
| 252 | |||
