ChangeSet 1.1321, 2005/03/18 15:14:45+00:00, kaf24@xxxxxxxxxxxxxxxxxxxx
Linux 2.6 now always uses writable page tables (even SMP builds). Also
use native definitions for atomic read-modify-write operations on
ptes. Fixed instruction emulator in Xen.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/page.h | 14 ---
linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h | 34
--------
linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable.h | 41
++--------
tools/tests/test_x86_emulator.c | 15 +++
xen/arch/x86/mm.c | 30
++++---
xen/arch/x86/x86_emulate.c | 27 +++---
xen/include/asm-x86/page.h | 21 ++++-
xen/include/asm-x86/x86_32/page.h | 5 -
xen/include/asm-x86/x86_64/page.h | 9 +-
9 files changed, 89 insertions(+), 107 deletions(-)
diff -Nru a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/page.h
b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/page.h
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/page.h 2005-03-18
11:03:51 -05:00
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/page.h 2005-03-18
11:03:51 -05:00
@@ -116,17 +116,11 @@
}
#define pgprot_val(x) ((x).pgprot)
-static inline pte_t __pte(unsigned long x)
-{
- if (x & 1) x = phys_to_machine(x);
- return ((pte_t) { (x) });
-}
+#define __pte(x) ({ unsigned long _x = (x); \
+ (((_x)&1) ? ((pte_t) {phys_to_machine(_x)}) : ((pte_t) {(_x)})); })
#define __pte_ma(x) ((pte_t) { (x) } )
-static inline pgd_t __pgd(unsigned long x)
-{
- if ((x & 1)) x = phys_to_machine(x);
- return ((pgd_t) { (x) });
-}
+#define __pgd(x) ({ unsigned long _x = (x); \
+ (((_x)&1) ? ((pgd_t) {phys_to_machine(_x)}) : ((pgd_t) {(_x)})); })
#define __pgprot(x) ((pgprot_t) { (x) } )
#endif /* !__ASSEMBLY__ */
diff -Nru a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
2005-03-18 11:03:51 -05:00
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
2005-03-18 11:03:51 -05:00
@@ -13,41 +13,13 @@
* within a page table are directly modified. Thus, the following
* hook is made available.
*/
-#define set_pte_batched(pteptr, pteval) \
- queue_l1_entry_update(pteptr, (pteval).pte_low)
-
-#ifdef CONFIG_SMP
-#define set_pte(pteptr, pteval) xen_l1_entry_update(pteptr, (pteval).pte_low)
-#if 0
-do { \
- (*(pteptr) = pteval); \
- HYPERVISOR_xen_version(0); \
-} while (0)
-#endif
-#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
-#else
#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
-#endif
#define set_pmd(pmdptr, pmdval) xen_l2_entry_update((pmdptr), (pmdval))
+#define set_pte_batched(pteptr, pteval) \
+ queue_l1_entry_update(pteptr, (pteval).pte_low)
-/*
- * A note on implementation of this atomic 'get-and-clear' operation.
- * This is actually very simple because Xen Linux can only run on a single
- * processor. Therefore, we cannot race other processors setting the 'accessed'
- * or 'dirty' bits on a page-table entry.
- * Even if pages are shared between domains, that is not a problem because
- * each domain will have separate page tables, with their own versions of
- * accessed & dirty state.
- */
-static inline pte_t ptep_get_and_clear(pte_t *xp)
-{
- pte_t pte = *xp;
- if (pte.pte_low)
- set_pte(xp, __pte_ma(0));
- return pte;
-}
-
+#define ptep_get_and_clear(xp) __pte_ma(xchg(&(xp)->pte_low, 0))
#define pte_same(a, b) ((a).pte_low == (b).pte_low)
/*
* We detect special mappings in one of two ways:
diff -Nru a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable.h
b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable.h
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable.h
2005-03-18 11:03:51 -05:00
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/pgtable.h
2005-03-18 11:03:51 -05:00
@@ -89,9 +89,6 @@
# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
#endif
-extern void *high_memory;
-extern unsigned long vmalloc_earlyreserve;
-
/*
* The 4MB page is guessing.. Detailed in the infamous "Chapter H"
* of the Pentium details, but assuming intel did the straightforward
@@ -214,7 +211,7 @@
/* pmd_present doesn't just test the _PAGE_PRESENT bit since wr.p.t.
can temporarily clear it. */
#define pmd_present(x) (pmd_val(x))
-/* pmd_clear below */
+#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER &
~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT))
@@ -254,34 +251,20 @@
static inline int ptep_test_and_clear_dirty(pte_t *ptep)
{
- pte_t pte = *ptep;
- int ret = pte_dirty(pte);
- if (ret)
- xen_l1_entry_update(ptep, pte_mkclean(pte).pte_low);
- return ret;
+ if (!pte_dirty(*ptep))
+ return 0;
+ return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low);
}
static inline int ptep_test_and_clear_young(pte_t *ptep)
{
- pte_t pte = *ptep;
- int ret = pte_young(pte);
- if (ret)
- xen_l1_entry_update(ptep, pte_mkold(pte).pte_low);
- return ret;
+ if (!pte_young(*ptep))
+ return 0;
+ return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
}
-static inline void ptep_set_wrprotect(pte_t *ptep)
-{
- pte_t pte = *ptep;
- if (pte_write(pte))
- set_pte(ptep, pte_wrprotect(pte));
-}
-static inline void ptep_mkdirty(pte_t *ptep)
-{
- pte_t pte = *ptep;
- if (!pte_dirty(pte))
- xen_l1_entry_update(ptep, pte_mkdirty(pte).pte_low);
-}
+static inline void ptep_set_wrprotect(pte_t *ptep) {
clear_bit(_PAGE_BIT_RW, &ptep->pte_low); }
+static inline void ptep_mkdirty(pte_t *ptep) {
set_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); }
/*
* Macro to mark a page protection value as "uncacheable". On processors
which do not support
@@ -316,11 +299,6 @@
#define page_pte(page) page_pte_prot(page, __pgprot(0))
-#define pmd_clear(xp) do { \
- set_pmd(xp, __pmd(0)); \
- xen_flush_page_update_queue(); \
-} while (0)
-
#define pmd_large(pmd) \
((pmd_val(pmd) & (_PAGE_PSE|_PAGE_PRESENT)) == (_PAGE_PSE|_PAGE_PRESENT))
@@ -416,7 +394,6 @@
*/
#define update_mmu_cache(vma,address,pte) do { } while (0)
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
do { \
if (__dirty) { \
diff -Nru a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c 2005-03-18 11:03:51 -05:00
+++ b/tools/tests/test_x86_emulator.c 2005-03-18 11:03:51 -05:00
@@ -158,6 +158,21 @@
goto fail;
printf("okay\n");
+ printf("%-40s", "Testing btrl $0x1,(%edi)...");
+ instr[0] = 0x0f; instr[1] = 0xba; instr[2] = 0x37; instr[3] = 0x01;
+ res = 0x2233445F;
+ regs.eflags = 0x200;
+ regs.eip = (unsigned long)&instr[0];
+ regs.edi = (unsigned long)&res;
+ cr2 = regs.edi;
+ rc = x86_emulate_memop(®s, cr2, &emulops, 4);
+ if ( (rc != 0) ||
+ (res != 0x2233445D) ||
+ ((regs.eflags&0x201) != 0x201) ||
+ (regs.eip != (unsigned long)&instr[4]) )
+ goto fail;
+ printf("okay\n");
+
return 0;
fail:
diff -Nru a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c 2005-03-18 11:03:51 -05:00
+++ b/xen/arch/x86/mm.c 2005-03-18 11:03:51 -05:00
@@ -2560,18 +2560,15 @@
/* Write page fault handler: check if guest is trying to modify a PTE. */
int ptwr_do_page_fault(unsigned long addr)
{
- unsigned long pte, pfn, l2e;
- struct pfn_info *page;
- l2_pgentry_t *pl2e;
- int which, cpu = smp_processor_id();
- u32 l2_idx;
-
-#ifdef __x86_64__
- return 0; /* Writable pagetables need fixing for x86_64. */
-#endif
+ unsigned long pte, pfn, l2e;
+ struct pfn_info *page;
+ l2_pgentry_t *pl2e;
+ int which, cpu = smp_processor_id();
+ u32 l2_idx;
+ struct exec_domain *ed = current;
/* Can't use linear_l2_table with external tables. */
- BUG_ON(shadow_mode_external(current->domain));
+ BUG_ON(shadow_mode_external(ed->domain));
/*
* Attempt to read the PTE that maps the VA being accessed. By checking for
@@ -2595,6 +2592,15 @@
return 0;
}
+ /* x86/64: Writable pagetable code needs auditing. Use emulator for now. */
+#if defined(__x86_64__)
+ goto emulate;
+#endif
+
+ /* Writable pagetables are not yet SMP safe. Use emulator for now. */
+ if ( (ed->eid != 0) || (ed->ed_next_list != NULL) )
+ goto emulate;
+
/* Get the L2 index at which this L1 p.t. is always mapped. */
l2_idx = page->u.inuse.type_info & PGT_va_mask;
if ( unlikely(l2_idx >= PGT_va_unknown) )
@@ -2640,7 +2646,7 @@
* If last batch made no updates then we are probably stuck. Emulate this
* update to ensure we make progress.
*/
- if ( (ptwr_info[cpu].ptinfo[which].prev_exec_domain == current) &&
+ if ( (ptwr_info[cpu].ptinfo[which].prev_exec_domain == ed) &&
(ptwr_info[cpu].ptinfo[which].prev_nr_updates == 0) )
{
/* Force non-emul next time, or we can get stuck emulating forever. */
@@ -2653,7 +2659,7 @@
/* For safety, disconnect the L1 p.t. page from current space. */
if ( (which == PTWR_PT_ACTIVE) &&
- likely(!shadow_mode_enabled(current->domain)) )
+ likely(!shadow_mode_enabled(ed->domain)) )
{
*pl2e = mk_l2_pgentry(l2e & ~_PAGE_PRESENT);
flush_tlb(); /* XXX Multi-CPU guests? */
diff -Nru a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c 2005-03-18 11:03:51 -05:00
+++ b/xen/arch/x86/x86_emulate.c 2005-03-18 11:03:51 -05:00
@@ -18,12 +18,14 @@
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/xen-changelog
|