aboutsummaryrefslogtreecommitdiffstats
path: root/extras/mini-os/arch
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-01-18 16:20:13 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-01-18 16:20:13 +0000
commit04383f9c0fe6f18446c8f273d9200fdda4f1afe3 (patch)
tree56fd028d8180f14f7fcf62ebb34a096f738a8479 /extras/mini-os/arch
parent0747f6e56ec0c2a019f6c76cadb34feca6e0f103 (diff)
downloadxen-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')
-rw-r--r--extras/mini-os/arch/x86/mm.c6
-rw-r--r--extras/mini-os/arch/x86/traps.c44
2 files changed, 49 insertions, 1 deletions
diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c
index 53becda146..b8f55b7c58 100644
--- a/extras/mini-os/arch/x86/mm.c
+++ b/extras/mini-os/arch/x86/mm.c
@@ -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");
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 */