diff options
author | Avi Kivity <avi@qumranet.com> | 2007-01-05 19:36:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2007-01-06 02:55:24 -0500 |
commit | ac79c978f173586ab3624427c89cd22b393cabd4 (patch) | |
tree | 43553aa9ac5839c6f63b95c2218c16ea2e35d570 /drivers/kvm/paging_tmpl.h | |
parent | 1342d3536d6a12541ceb276da15f043db90716eb (diff) |
[PATCH] KVM: MMU: Fold fetch_guest() into init_walker()
It is never necessary to fetch a guest entry from an intermediate page table
level (except for large pages), so avoid some confusion by always descending
into the lowest possible level.
Rename init_walker() to walk_addr() as it is no longer restricted to
initialization.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/kvm/paging_tmpl.h')
-rw-r--r-- | drivers/kvm/paging_tmpl.h | 105 |
1 files changed, 47 insertions, 58 deletions
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 3a35c8067dec..963d80e2271f 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h | |||
@@ -54,14 +54,19 @@ struct guest_walker { | |||
54 | int level; | 54 | int level; |
55 | gfn_t table_gfn; | 55 | gfn_t table_gfn; |
56 | pt_element_t *table; | 56 | pt_element_t *table; |
57 | pt_element_t *ptep; | ||
57 | pt_element_t inherited_ar; | 58 | pt_element_t inherited_ar; |
58 | }; | 59 | }; |
59 | 60 | ||
60 | static void FNAME(init_walker)(struct guest_walker *walker, | 61 | /* |
61 | struct kvm_vcpu *vcpu) | 62 | * Fetch a guest pte for a guest virtual address |
63 | */ | ||
64 | static void FNAME(walk_addr)(struct guest_walker *walker, | ||
65 | struct kvm_vcpu *vcpu, gva_t addr) | ||
62 | { | 66 | { |
63 | hpa_t hpa; | 67 | hpa_t hpa; |
64 | struct kvm_memory_slot *slot; | 68 | struct kvm_memory_slot *slot; |
69 | pt_element_t *ptep; | ||
65 | 70 | ||
66 | walker->level = vcpu->mmu.root_level; | 71 | walker->level = vcpu->mmu.root_level; |
67 | walker->table_gfn = (vcpu->cr3 & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; | 72 | walker->table_gfn = (vcpu->cr3 & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; |
@@ -75,6 +80,38 @@ static void FNAME(init_walker)(struct guest_walker *walker, | |||
75 | walker->table = (pt_element_t *)( (unsigned long)walker->table | | 80 | walker->table = (pt_element_t *)( (unsigned long)walker->table | |
76 | (unsigned long)(vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) ); | 81 | (unsigned long)(vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) ); |
77 | walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; | 82 | walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; |
83 | |||
84 | for (;;) { | ||
85 | int index = PT_INDEX(addr, walker->level); | ||
86 | hpa_t paddr; | ||
87 | |||
88 | ptep = &walker->table[index]; | ||
89 | ASSERT(((unsigned long)walker->table & PAGE_MASK) == | ||
90 | ((unsigned long)ptep & PAGE_MASK)); | ||
91 | |||
92 | /* Don't set accessed bit on PAE PDPTRs */ | ||
93 | if (vcpu->mmu.root_level != 3 || walker->level != 3) | ||
94 | if ((*ptep & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) | ||
95 | == PT_PRESENT_MASK) | ||
96 | *ptep |= PT_ACCESSED_MASK; | ||
97 | |||
98 | if (!is_present_pte(*ptep) || | ||
99 | walker->level == PT_PAGE_TABLE_LEVEL || | ||
100 | (walker->level == PT_DIRECTORY_LEVEL && | ||
101 | (*ptep & PT_PAGE_SIZE_MASK) && | ||
102 | (PTTYPE == 64 || is_pse(vcpu)))) | ||
103 | break; | ||
104 | |||
105 | if (walker->level != 3 || is_long_mode(vcpu)) | ||
106 | walker->inherited_ar &= walker->table[index]; | ||
107 | walker->table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; | ||
108 | paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK); | ||
109 | kunmap_atomic(walker->table, KM_USER0); | ||
110 | walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT), | ||
111 | KM_USER0); | ||
112 | --walker->level; | ||
113 | } | ||
114 | walker->ptep = ptep; | ||
78 | } | 115 | } |
79 | 116 | ||
80 | static void FNAME(release_walker)(struct guest_walker *walker) | 117 | static void FNAME(release_walker)(struct guest_walker *walker) |
@@ -110,41 +147,6 @@ static void FNAME(set_pde)(struct kvm_vcpu *vcpu, u64 guest_pde, | |||
110 | } | 147 | } |
111 | 148 | ||
112 | /* | 149 | /* |
113 | * Fetch a guest pte from a specific level in the paging hierarchy. | ||
114 | */ | ||
115 | static pt_element_t *FNAME(fetch_guest)(struct kvm_vcpu *vcpu, | ||
116 | struct guest_walker *walker, | ||
117 | int level, | ||
118 | gva_t addr) | ||
119 | { | ||
120 | |||
121 | ASSERT(level > 0 && level <= walker->level); | ||
122 | |||
123 | for (;;) { | ||
124 | int index = PT_INDEX(addr, walker->level); | ||
125 | hpa_t paddr; | ||
126 | |||
127 | ASSERT(((unsigned long)walker->table & PAGE_MASK) == | ||
128 | ((unsigned long)&walker->table[index] & PAGE_MASK)); | ||
129 | if (level == walker->level || | ||
130 | !is_present_pte(walker->table[index]) || | ||
131 | (walker->level == PT_DIRECTORY_LEVEL && | ||
132 | (walker->table[index] & PT_PAGE_SIZE_MASK) && | ||
133 | (PTTYPE == 64 || is_pse(vcpu)))) | ||
134 | return &walker->table[index]; | ||
135 | if (walker->level != 3 || is_long_mode(vcpu)) | ||
136 | walker->inherited_ar &= walker->table[index]; | ||
137 | walker->table_gfn = (walker->table[index] & PT_BASE_ADDR_MASK) | ||
138 | >> PAGE_SHIFT; | ||
139 | paddr = safe_gpa_to_hpa(vcpu, walker->table[index] & PT_BASE_ADDR_MASK); | ||
140 | kunmap_atomic(walker->table, KM_USER0); | ||
141 | walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT), | ||
142 | KM_USER0); | ||
143 | --walker->level; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Fetch a shadow pte for a specific level in the paging hierarchy. | 150 | * Fetch a shadow pte for a specific level in the paging hierarchy. |
149 | */ | 151 | */ |
150 | static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | 152 | static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, |
@@ -153,6 +155,10 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
153 | hpa_t shadow_addr; | 155 | hpa_t shadow_addr; |
154 | int level; | 156 | int level; |
155 | u64 *prev_shadow_ent = NULL; | 157 | u64 *prev_shadow_ent = NULL; |
158 | pt_element_t *guest_ent = walker->ptep; | ||
159 | |||
160 | if (!is_present_pte(*guest_ent)) | ||
161 | return NULL; | ||
156 | 162 | ||
157 | shadow_addr = vcpu->mmu.root_hpa; | 163 | shadow_addr = vcpu->mmu.root_hpa; |
158 | level = vcpu->mmu.shadow_root_level; | 164 | level = vcpu->mmu.shadow_root_level; |
@@ -160,7 +166,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
160 | for (; ; level--) { | 166 | for (; ; level--) { |
161 | u32 index = SHADOW_PT_INDEX(addr, level); | 167 | u32 index = SHADOW_PT_INDEX(addr, level); |
162 | u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index; | 168 | u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index; |
163 | pt_element_t *guest_ent; | ||
164 | u64 shadow_pte; | 169 | u64 shadow_pte; |
165 | 170 | ||
166 | if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { | 171 | if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { |
@@ -171,21 +176,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
171 | continue; | 176 | continue; |
172 | } | 177 | } |
173 | 178 | ||
174 | if (PTTYPE == 32 && level > PT32_ROOT_LEVEL) { | ||
175 | ASSERT(level == PT32E_ROOT_LEVEL); | ||
176 | guest_ent = FNAME(fetch_guest)(vcpu, walker, | ||
177 | PT32_ROOT_LEVEL, addr); | ||
178 | } else | ||
179 | guest_ent = FNAME(fetch_guest)(vcpu, walker, | ||
180 | level, addr); | ||
181 | |||
182 | if (!is_present_pte(*guest_ent)) | ||
183 | return NULL; | ||
184 | |||
185 | /* Don't set accessed bit on PAE PDPTRs */ | ||
186 | if (vcpu->mmu.root_level != 3 || walker->level != 3) | ||
187 | *guest_ent |= PT_ACCESSED_MASK; | ||
188 | |||
189 | if (level == PT_PAGE_TABLE_LEVEL) { | 179 | if (level == PT_PAGE_TABLE_LEVEL) { |
190 | 180 | ||
191 | if (walker->level == PT_DIRECTORY_LEVEL) { | 181 | if (walker->level == PT_DIRECTORY_LEVEL) { |
@@ -253,7 +243,7 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu, | |||
253 | *shadow_ent &= ~PT_USER_MASK; | 243 | *shadow_ent &= ~PT_USER_MASK; |
254 | } | 244 | } |
255 | 245 | ||
256 | guest_ent = FNAME(fetch_guest)(vcpu, walker, PT_PAGE_TABLE_LEVEL, addr); | 246 | guest_ent = walker->ptep; |
257 | 247 | ||
258 | if (!is_present_pte(*guest_ent)) { | 248 | if (!is_present_pte(*guest_ent)) { |
259 | *shadow_ent = 0; | 249 | *shadow_ent = 0; |
@@ -296,7 +286,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, | |||
296 | * Look up the shadow pte for the faulting address. | 286 | * Look up the shadow pte for the faulting address. |
297 | */ | 287 | */ |
298 | for (;;) { | 288 | for (;;) { |
299 | FNAME(init_walker)(&walker, vcpu); | 289 | FNAME(walk_addr)(&walker, vcpu, addr); |
300 | shadow_pte = FNAME(fetch)(vcpu, addr, &walker); | 290 | shadow_pte = FNAME(fetch)(vcpu, addr, &walker); |
301 | if (IS_ERR(shadow_pte)) { /* must be -ENOMEM */ | 291 | if (IS_ERR(shadow_pte)) { /* must be -ENOMEM */ |
302 | nonpaging_flush(vcpu); | 292 | nonpaging_flush(vcpu); |
@@ -357,9 +347,8 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) | |||
357 | pt_element_t guest_pte; | 347 | pt_element_t guest_pte; |
358 | gpa_t gpa; | 348 | gpa_t gpa; |
359 | 349 | ||
360 | FNAME(init_walker)(&walker, vcpu); | 350 | FNAME(walk_addr)(&walker, vcpu, vaddr); |
361 | guest_pte = *FNAME(fetch_guest)(vcpu, &walker, PT_PAGE_TABLE_LEVEL, | 351 | guest_pte = *walker.ptep; |
362 | vaddr); | ||
363 | FNAME(release_walker)(&walker); | 352 | FNAME(release_walker)(&walker); |
364 | 353 | ||
365 | if (!is_present_pte(guest_pte)) | 354 | if (!is_present_pte(guest_pte)) |