aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-06-16 07:30:02 -0400
committerIngo Molnar <mingo@elte.hu>2008-06-25 09:17:23 -0400
commite57778a1e30470c9f5b79e370511b9af29b59c48 (patch)
tree01239f16b016d57206ba8bdfcbd443d8a26cd5e4
parent08b882c627aeeeb3cfd3c4354f0d360d7949549d (diff)
xen: implement ptep_modify_prot_start/commit
Xen has a pte update function which will update a pte while preserving its accessed and dirty bits. This means that ptep_modify_prot_start() can be implemented as a simple read of the pte value. The hardware may update the pte in the meantime, but ptep_modify_prot_commit() updates it while preserving any changes that may have happened in the meantime. The updates in ptep_modify_prot_commit() are batched if we're currently in lazy mmu mode. The mmu_update hypercall can take a batch of updates to perform, but this code doesn't make particular use of that feature, in favour of using generic multicall batching to get them all into the hypervisor. The net effect of this is that each mprotect pte update turns from two expensive trap-and-emulate faults into they hypervisor into a single hypercall whose cost is amortized in a batched multicall. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Acked-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/xen/enlighten.c13
-rw-r--r--arch/x86/xen/mmu.c21
-rw-r--r--arch/x86/xen/mmu.h4
-rw-r--r--include/xen/interface/features.h3
-rw-r--r--include/xen/interface/xen.h9
5 files changed, 45 insertions, 5 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 0b7553cbc52..bd74229081c 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -168,7 +168,9 @@ static void __init xen_banner(void)
168{ 168{
169 printk(KERN_INFO "Booting paravirtualized kernel on %s\n", 169 printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
170 pv_info.name); 170 pv_info.name);
171 printk(KERN_INFO "Hypervisor signature: %s\n", xen_start_info->magic); 171 printk(KERN_INFO "Hypervisor signature: %s%s\n",
172 xen_start_info->magic,
173 xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
172} 174}
173 175
174static void xen_cpuid(unsigned int *ax, unsigned int *bx, 176static void xen_cpuid(unsigned int *ax, unsigned int *bx,
@@ -1243,6 +1245,8 @@ asmlinkage void __init xen_start_kernel(void)
1243 1245
1244 BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0); 1246 BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0);
1245 1247
1248 xen_setup_features();
1249
1246 /* Install Xen paravirt ops */ 1250 /* Install Xen paravirt ops */
1247 pv_info = xen_info; 1251 pv_info = xen_info;
1248 pv_init_ops = xen_init_ops; 1252 pv_init_ops = xen_init_ops;
@@ -1252,14 +1256,17 @@ asmlinkage void __init xen_start_kernel(void)
1252 pv_apic_ops = xen_apic_ops; 1256 pv_apic_ops = xen_apic_ops;
1253 pv_mmu_ops = xen_mmu_ops; 1257 pv_mmu_ops = xen_mmu_ops;
1254 1258
1259 if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
1260 pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start;
1261 pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit;
1262 }
1263
1255 machine_ops = xen_machine_ops; 1264 machine_ops = xen_machine_ops;
1256 1265
1257#ifdef CONFIG_SMP 1266#ifdef CONFIG_SMP
1258 smp_ops = xen_smp_ops; 1267 smp_ops = xen_smp_ops;
1259#endif 1268#endif
1260 1269
1261 xen_setup_features();
1262
1263 /* Get mfn list */ 1270 /* Get mfn list */
1264 if (!xen_feature(XENFEAT_auto_translated_physmap)) 1271 if (!xen_feature(XENFEAT_auto_translated_physmap))
1265 xen_build_dynamic_phys_to_machine(); 1272 xen_build_dynamic_phys_to_machine();
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 8132aa8c5d4..846dad7d54a 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -323,6 +323,27 @@ out:
323 preempt_enable(); 323 preempt_enable();
324} 324}
325 325
326pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
327{
328 /* Just return the pte as-is. We preserve the bits on commit */
329 return *ptep;
330}
331
332void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
333 pte_t *ptep, pte_t pte)
334{
335 struct multicall_space mcs;
336 struct mmu_update *u;
337
338 mcs = xen_mc_entry(sizeof(*u));
339 u = mcs.args;
340 u->ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
341 u->val = pte_val_ma(pte);
342 MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
343
344 xen_mc_issue(PARAVIRT_LAZY_MMU);
345}
346
326/* Assume pteval_t is equivalent to all the other *val_t types. */ 347/* Assume pteval_t is equivalent to all the other *val_t types. */
327static pteval_t pte_mfn_to_pfn(pteval_t val) 348static pteval_t pte_mfn_to_pfn(pteval_t val)
328{ 349{
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index e3dd09e25c6..297bf9f5b8b 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -52,4 +52,8 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val);
52void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); 52void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
53void xen_pmd_clear(pmd_t *pmdp); 53void xen_pmd_clear(pmd_t *pmdp);
54 54
55pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
56void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
57 pte_t *ptep, pte_t pte);
58
55#endif /* _XEN_MMU_H */ 59#endif /* _XEN_MMU_H */
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h
index d73228d1648..f51b6413b05 100644
--- a/include/xen/interface/features.h
+++ b/include/xen/interface/features.h
@@ -38,6 +38,9 @@
38 */ 38 */
39#define XENFEAT_pae_pgdir_above_4gb 4 39#define XENFEAT_pae_pgdir_above_4gb 4
40 40
41/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */
42#define XENFEAT_mmu_pt_update_preserve_ad 5
43
41#define XENFEAT_NR_SUBMAPS 1 44#define XENFEAT_NR_SUBMAPS 1
42 45
43#endif /* __XEN_PUBLIC_FEATURES_H__ */ 46#endif /* __XEN_PUBLIC_FEATURES_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 819a0331cda..2befa3e2f1b 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -114,9 +114,14 @@
114 * ptr[:2] -- Machine address within the frame whose mapping to modify. 114 * ptr[:2] -- Machine address within the frame whose mapping to modify.
115 * The frame must belong to the FD, if one is specified. 115 * The frame must belong to the FD, if one is specified.
116 * val -- Value to write into the mapping entry. 116 * val -- Value to write into the mapping entry.
117 *
118 * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD:
119 * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed
120 * with those in @val.
117 */ 121 */
118#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */ 122#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
119#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */ 123#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */
124#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */
120 125
121/* 126/*
122 * MMU EXTENDED OPERATIONS 127 * MMU EXTENDED OPERATIONS