diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-01-18 16:20:13 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-01-18 16:20:13 +0000 |
commit | 04383f9c0fe6f18446c8f273d9200fdda4f1afe3 (patch) | |
tree | 56fd028d8180f14f7fcf62ebb34a096f738a8479 /extras/mini-os/arch/x86/traps.c | |
parent | 0747f6e56ec0c2a019f6c76cadb34feca6e0f103 (diff) | |
download | xen-04383f9c0fe6f18446c8f273d9200fdda4f1afe3.tar.gz xen-04383f9c0fe6f18446c8f273d9200fdda4f1afe3.tar.bz2 xen-04383f9c0fe6f18446c8f273d9200fdda4f1afe3.zip |
minios: support COW for a zero page
Permits to support sparse data.
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
Diffstat (limited to 'extras/mini-os/arch/x86/traps.c')
-rw-r--r-- | extras/mini-os/arch/x86/traps.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/extras/mini-os/arch/x86/traps.c b/extras/mini-os/arch/x86/traps.c index 292c48b22b..2d65c312d2 100644 --- a/extras/mini-os/arch/x86/traps.c +++ b/extras/mini-os/arch/x86/traps.c @@ -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 */ |