ia64/xen-unstable

changeset 10475:5d44f3ab9950

[XEN] Fix ptwr_do_page_fault() after new more permissive
entry conditions to that function. Now that we no longer
check PGERR_page_present (i.e., that fault is a protection
fault), because it's not safe to do so, we can enter
ptwr_do_page_fault() with a not-present L2 page directory.
We then crash on our first access to the linear_l2_table.
This patch fixes all unprotected accesses to the
linear_l2_table to correctly handle faults.

Also move setup of globally-visible ptwr info record to end
of ptwr_do_page_fault(). We don't want the info picked up
by reentrant invocations of the page-fault handler.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@dhcp93.uk.xensource.com
date Mon Jun 19 10:18:39 2006 +0100 (2006-06-19)
parents 8eab9f3cdb1a
children db37448ffe97
files xen/arch/x86/mm.c
line diff
     1.1 --- a/xen/arch/x86/mm.c	Sun Jun 18 19:49:31 2006 +0100
     1.2 +++ b/xen/arch/x86/mm.c	Mon Jun 19 10:18:39 2006 +0100
     1.3 @@ -3495,11 +3495,13 @@ int ptwr_do_page_fault(struct domain *d,
     1.4      /*
     1.5       * Attempt to read the PTE that maps the VA being accessed. By checking for
     1.6       * PDE validity in the L2 we avoid many expensive fixups in __get_user().
     1.7 -     * NB. The L2 entry cannot be detached as the caller already checked that.
     1.8 +     * NB. The L2 entry cannot be detached due to existing ptwr work: the
     1.9 +     * caller already checked that.
    1.10       */
    1.11 -    if ( !(l2e_get_flags(__linear_l2_table[l2_linear_offset(addr)]) &
    1.12 -           _PAGE_PRESENT) ||
    1.13 -         __copy_from_user(&pte,&linear_pg_table[l1_linear_offset(addr)],
    1.14 +    pl2e = &__linear_l2_table[l2_linear_offset(addr)];
    1.15 +    if ( __copy_from_user(&l2e, pl2e, sizeof(l2e)) ||
    1.16 +        !(l2e_get_flags(l2e) & _PAGE_PRESENT) ||
    1.17 +         __copy_from_user(&pte, &linear_pg_table[l1_linear_offset(addr)],
    1.18                            sizeof(pte)) )
    1.19      {
    1.20          return 0;
    1.21 @@ -3617,18 +3619,16 @@ int ptwr_do_page_fault(struct domain *d,
    1.22                  "pfn %lx\n", PTWR_PRINT_WHICH, addr,
    1.23                  l2_idx << L2_PAGETABLE_SHIFT, pfn);
    1.24  
    1.25 -    d->arch.ptwr[which].l1va   = addr | 1;
    1.26 -    d->arch.ptwr[which].l2_idx = l2_idx;
    1.27 -    d->arch.ptwr[which].vcpu   = current;
    1.28 -
    1.29 -#ifdef PERF_ARRAYS
    1.30 -    d->arch.ptwr[which].eip    = regs->eip;
    1.31 -#endif
    1.32 -
    1.33      /* For safety, disconnect the L1 p.t. page from current space. */
    1.34      if ( which == PTWR_PT_ACTIVE )
    1.35      {
    1.36 -        l2e_remove_flags(*pl2e, _PAGE_PRESENT);
    1.37 +        l2e_remove_flags(l2e, _PAGE_PRESENT);
    1.38 +        if ( unlikely(__copy_to_user(pl2e, &l2e, sizeof(l2e))) )
    1.39 +        {
    1.40 +            MEM_LOG("ptwr: Could not unhook l2e at %p", pl2e);
    1.41 +            domain_crash(d);
    1.42 +            return 0;
    1.43 +        }
    1.44          flush_tlb_mask(d->domain_dirty_cpumask);
    1.45      }
    1.46      
    1.47 @@ -3642,14 +3642,24 @@ int ptwr_do_page_fault(struct domain *d,
    1.48      if ( unlikely(__put_user(pte.l1,
    1.49                               &linear_pg_table[l1_linear_offset(addr)].l1)) )
    1.50      {
    1.51 -        MEM_LOG("ptwr: Could not update pte at %p", (unsigned long *)
    1.52 +        MEM_LOG("ptwr: Could not update pte at %p",
    1.53                  &linear_pg_table[l1_linear_offset(addr)]);
    1.54 -        /* Toss the writable pagetable state and crash. */
    1.55 -        d->arch.ptwr[which].l1va = 0;
    1.56          domain_crash(d);
    1.57          return 0;
    1.58      }
    1.59      
    1.60 +    /*
    1.61 +     * Now record the writable pagetable state *after* any accesses that can
    1.62 +     * cause a recursive page fault (i.e., those via the *_user() accessors).
    1.63 +     * Otherwise we can enter ptwr_flush() with half-done ptwr state.
    1.64 +     */
    1.65 +    d->arch.ptwr[which].l1va   = addr | 1;
    1.66 +    d->arch.ptwr[which].l2_idx = l2_idx;
    1.67 +    d->arch.ptwr[which].vcpu   = current;
    1.68 +#ifdef PERF_ARRAYS
    1.69 +    d->arch.ptwr[which].eip    = regs->eip;
    1.70 +#endif
    1.71 +
    1.72      return EXCRET_fault_fixed;
    1.73  
    1.74   emulate: