ia64/xen-unstable

changeset 1066:7eb512e5106d

bitkeeper revision 1.705 (40226014Y-RJhXC4XKyIIvcyJtSHuQ)

memory.c, domain.c:
Extend support for linear page tables by allowing page directories to map one another.
author kaf24@scramble.cl.cam.ac.uk
date Thu Feb 05 15:24:04 2004 +0000 (2004-02-05)
parents 9acedaeb47e2
children 3de90982de3f
files xen/common/domain.c xen/common/memory.c
line diff
     1.1 --- a/xen/common/domain.c	Wed Feb 04 21:48:17 2004 +0000
     1.2 +++ b/xen/common/domain.c	Thu Feb 05 15:24:04 2004 +0000
     1.3 @@ -343,6 +343,7 @@ void free_all_dom_mem(struct task_struct
     1.4  {
     1.5      struct list_head *ent, zombies;
     1.6      struct pfn_info *page;
     1.7 +    unsigned long x, y;
     1.8  
     1.9      INIT_LIST_HEAD(&zombies);
    1.10  
    1.11 @@ -394,6 +395,24 @@ void free_all_dom_mem(struct task_struct
    1.12          if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
    1.13              put_page(page);
    1.14  
    1.15 +        /*
    1.16 +         * Forcibly invalidate L2 tables at this point to break circular
    1.17 +         * 'linear page table' references. This is okay because MMU structures
    1.18 +         * are not shared across domains and this domain is now dead. Thus L2
    1.19 +         * tables are not in use so a non-zero count means circular reference.
    1.20 +         */
    1.21 +        y = page->type_and_flags;
    1.22 +        do {
    1.23 +            x = y;
    1.24 +            if ( likely((x & (PGT_type_mask|PGT_validated)) != 
    1.25 +                        (PGT_l2_page_table|PGT_validated)) )
    1.26 +                break;
    1.27 +            y = cmpxchg(&page->type_and_flags, x, x & ~PGT_validated);
    1.28 +            if ( likely(y == x) )
    1.29 +                free_page_type(page, PGT_l2_page_table);
    1.30 +        }
    1.31 +        while ( unlikely(y != x) );
    1.32 +
    1.33          put_page(page);
    1.34      }
    1.35  }
     2.1 --- a/xen/common/memory.c	Wed Feb 04 21:48:17 2004 +0000
     2.2 +++ b/xen/common/memory.c	Thu Feb 05 15:24:04 2004 +0000
     2.3 @@ -346,11 +346,22 @@ static int get_page_and_type_from_pagenr
     2.4  
     2.5  
     2.6  /*
     2.7 - * We allow an L2 table to map itself, to achieve a linear p.t. Note that this
     2.8 - * does not raise any reference counts.
     2.9 + * We allow an L2 tables to map each other (a.k.a. linear page tables). It
    2.10 + * needs some special care with reference counst and access permissions:
    2.11 + *  1. The mapping entry must be read-only, or the guest may get write access
    2.12 + *     to its own PTEs.
    2.13 + *  2. We must only bump the reference counts for an *already validated*
    2.14 + *     L2 table, or we can end up in a deadlock in get_page_type() by waiting
    2.15 + *     on a validation that is required to complete that validation.
    2.16 + *  3. We only need to increment the reference counts for the mapped page
    2.17 + *     frame if it is mapped by a different L2 table. This is sufficient and
    2.18 + *     also necessary to allow validation of an L2 table mapping itself.
    2.19   */
    2.20 -static int check_linear_pagetable(l2_pgentry_t l2e, unsigned long pfn)
    2.21 +static int get_linear_pagetable(l2_pgentry_t l2e, unsigned long pfn)
    2.22  {
    2.23 +    unsigned long x, y;
    2.24 +    struct pfn_info *page;
    2.25 +
    2.26      if ( (l2_pgentry_val(l2e) & _PAGE_RW) )
    2.27      {
    2.28          MEM_LOG("Attempt to create linear p.t. with write perms");
    2.29 @@ -359,8 +370,27 @@ static int check_linear_pagetable(l2_pge
    2.30  
    2.31      if ( (l2_pgentry_val(l2e) >> PAGE_SHIFT) != pfn )
    2.32      {
    2.33 -        MEM_LOG("L2 tables may not map _other_ L2 tables!\n");
    2.34 -        return 0;
    2.35 +        /* Make sure the mapped frame belongs to the correct domain. */
    2.36 +        if ( unlikely(!get_page_from_pagenr(l2_pgentry_to_pagenr(l2e))) )
    2.37 +            return 0;
    2.38 +
    2.39 +        /*
    2.40 +         * Make sure that the mapped frame is an already-validated L2 table. 
    2.41 +         * If so, atomically increment the count (checking for overflow).
    2.42 +         */
    2.43 +        page = &frame_table[l2_pgentry_to_pagenr(l2e)];
    2.44 +        y = page->type_and_flags;
    2.45 +        do {
    2.46 +            x = y;
    2.47 +            if ( unlikely((x & PGT_count_mask) == PGT_count_mask) ||
    2.48 +                 unlikely((x & (PGT_type_mask|PGT_validated)) != 
    2.49 +                          (PGT_l2_page_table|PGT_validated)) )
    2.50 +            {
    2.51 +                put_page(page);
    2.52 +                return 0;
    2.53 +            }
    2.54 +        }
    2.55 +        while ( (y = cmpxchg(&page->type_and_flags, x, x + 1)) != x );
    2.56      }
    2.57  
    2.58      return 1;
    2.59 @@ -406,7 +436,7 @@ static int get_page_from_l2e(l2_pgentry_
    2.60  
    2.61      if ( unlikely(!get_page_and_type_from_pagenr(
    2.62          l2_pgentry_to_pagenr(l2e), PGT_l1_page_table)) )
    2.63 -        return check_linear_pagetable(l2e, pfn);
    2.64 +        return get_linear_pagetable(l2e, pfn);
    2.65  
    2.66      return 1;
    2.67  }
    2.68 @@ -434,7 +464,10 @@ static void put_page_from_l1e(l1_pgentry
    2.69  }
    2.70  
    2.71  
    2.72 -/* NB. Virtual address 'l2e' maps to a machine address within frame 'pfn'. */
    2.73 +/*
    2.74 + * NB. Virtual address 'l2e' maps to a machine address within frame 'pfn'.
    2.75 + * Note also that this automatically deals correctly with linear p.t.'s.
    2.76 + */
    2.77  static void put_page_from_l2e(l2_pgentry_t l2e, unsigned long pfn)
    2.78  {
    2.79      ASSERT(l2_pgentry_val(l2e) & _PAGE_PRESENT);