]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/mini-os.git/commitdiff
minios: support COW for a zero page
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 18 Jan 2008 16:20:13 +0000 (16:20 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 18 Jan 2008 16:20:13 +0000 (16:20 +0000)
Permits to support sparse data.
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
arch/x86/mm.c
arch/x86/traps.c
include/ia64/arch_mm.h
include/types.h
include/x86/arch_mm.h
include/x86/traps.h

index 53becda146bd769bbe5a4cd443c9907586686e8c..b8f55b7c58ac4bf683ea02eb26dacfea3e0c001a 100644 (file)
@@ -50,6 +50,7 @@
 #endif
 
 unsigned long *phys_to_machine_mapping;
+unsigned long mfn_zero;
 extern char stack[];
 extern void page_walk(unsigned long virt_addr);
 
@@ -492,10 +493,13 @@ void *map_frames_ex(unsigned long *f, unsigned long n, unsigned long stride,
 static void clear_bootstrap(void)
 {
     struct xen_memory_reservation reservation;
-    xen_pfn_t mfns[] = { virt_to_mfn(0), virt_to_mfn(&shared_info) };
+    xen_pfn_t mfns[] = { virt_to_mfn(&shared_info) };
     int n = sizeof(mfns)/sizeof(*mfns);
     pte_t nullpte = { };
 
+    /* Use page 0 as the CoW zero page */
+    memset(NULL, 0, PAGE_SIZE);
+    mfn_zero = pfn_to_mfn(0);
     if (HYPERVISOR_update_va_mapping(0, nullpte, UVMF_INVLPG))
        printk("Unable to unmap page 0\n");
 
index 292c48b22ba1a77802da9ec9a3dd03701ee0710b..2d65c312d2eec1a8cf6471019c6173ee5a77987a 100644 (file)
@@ -118,6 +118,46 @@ void page_walk(unsigned long virt_address)
 
 }
 
+static int handle_cow(unsigned long addr) {
+        pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;
+       unsigned long new_page;
+       int rc;
+
+#if defined(__x86_64__)
+        page = tab[l4_table_offset(addr)];
+       if (!(page & _PAGE_PRESENT))
+           return 0;
+        tab = pte_to_virt(page);
+#endif
+#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
+        page = tab[l3_table_offset(addr)];
+       if (!(page & _PAGE_PRESENT))
+           return 0;
+        tab = pte_to_virt(page);
+#endif
+        page = tab[l2_table_offset(addr)];
+       if (!(page & _PAGE_PRESENT))
+           return 0;
+        tab = pte_to_virt(page);
+        
+        page = tab[l1_table_offset(addr)];
+       if (!(page & _PAGE_PRESENT))
+           return 0;
+       /* Only support CoW for the zero page.  */
+       if (PHYS_PFN(page) != mfn_zero)
+           return 0;
+
+       new_page = alloc_pages(0);
+       memset((void*) new_page, 0, PAGE_SIZE);
+
+       rc = HYPERVISOR_update_va_mapping(addr & PAGE_MASK, __pte(virt_to_mach(new_page) | L1_PROT), UVMF_INVLPG);
+       if (!rc)
+               return 1;
+
+       printk("Map zero page to %lx failed: %d.\n", addr, rc);
+       return 0;
+}
+
 #define read_cr2() \
         (HYPERVISOR_shared_info->vcpu_info[smp_processor_id()].arch.cr2)
 
@@ -126,6 +166,10 @@ static int handling_pg_fault = 0;
 void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
     unsigned long addr = read_cr2();
+
+    if ((error_code & TRAP_PF_WRITE) && handle_cow(addr))
+       return;
+
     /* If we are already handling a page fault, and got another one
        that means we faulted in pagetable walk. Continuing here would cause
        a recursive fault */       
index c1506ac9885c61bd4537342ab964c8588f1d4d3a..1ade8996f115ea523613a2f4d6446a26d8a16c0f 100644 (file)
@@ -37,5 +37,7 @@
 #define STACK_SIZE              (PAGE_SIZE * (1 << STACK_SIZE_PAGE_ORDER))
 
 #define map_frames(f, n) map_frames_ex(f, n, 1, 0, 1, DOMID_SELF, 0, 0)
+/* TODO */
+#define map_zero(n, a) map_frames_ex(NULL, n, 0, 0, a, DOMID_SELF, 0, 0)
 
 #endif /* __ARCH_MM_H__ */
index d1b23c3a64e375a2a8bfeeb829d0df540242eefa..8767643b0dda5fa565151305fa0ed0721e931fd8 100644 (file)
@@ -57,6 +57,13 @@ typedef unsigned long       uintptr_t;
 typedef struct { unsigned long pte; } pte_t;
 #endif /* __i386__ || __x86_64__ */
 
+#if !defined(CONFIG_X86_PAE)
+#define __pte(x) ((pte_t) { (x) } )
+#else
+#define __pte(x) ({ unsigned long long _x = (x);        \
+    ((pte_t) {(unsigned long)(_x), (unsigned long)(_x>>32)}); })
+#endif
+
 typedef  u8 uint8_t;
 typedef  s8 int8_t;
 typedef u16 uint16_t;
index 8ae845131a00e7ba813a3916b9a98cb0ebe47988..1ed2755be7627ddec996a5479dcb46219fcd8bb5 100644 (file)
@@ -144,12 +144,14 @@ typedef unsigned long pgentry_t;
 
 #if defined(__i386__)
 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L1_PROT_RO (_PAGE_PRESENT|_PAGE_ACCESSED)
 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY |_PAGE_USER)
 #if defined(CONFIG_X86_PAE)
 #define L3_PROT (_PAGE_PRESENT)
 #endif /* CONFIG_X86_PAE */
 #elif defined(__x86_64__)
 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
+#define L1_PROT_RO (_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_USER)
 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
 #define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
 #define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
@@ -190,6 +192,7 @@ typedef unsigned long maddr_t;
 
 extern unsigned long *phys_to_machine_mapping;
 extern char _text, _etext, _erodata, _edata, _end;
+extern unsigned long mfn_zero;
 #define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
 static __inline__ maddr_t phys_to_machine(paddr_t phys)
 {
@@ -224,5 +227,6 @@ static __inline__ paddr_t machine_to_phys(maddr_t machine)
 #define pte_to_virt(_pte)          to_virt(mfn_to_pfn(pte_to_mfn(_pte)) << PAGE_SHIFT)
 
 #define map_frames(f, n) map_frames_ex(f, n, 1, 0, 1, DOMID_SELF, 0, L1_PROT)
+#define map_zero(n, a) map_frames_ex(&mfn_zero, n, 0, 0, a, DOMID_SELF, 0, L1_PROT_RO)
 
 #endif /* _ARCH_MM_H_ */
index 2f54fd28f0ecde4a1307b275bbd2a1b8777b2576..c3b504b986c67d419b8c8d7ef8470172e7158309 100644 (file)
@@ -70,4 +70,8 @@ struct pt_regs {
 
 void dump_regs(struct pt_regs *regs);
 
+#define TRAP_PF_PROT   0x1
+#define TRAP_PF_WRITE  0x2
+#define TRAP_PF_USER   0x4
+
 #endif /* _TRAPS_H_ */