aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbd240@boulderdash.cl.cam.ac.uk <bd240@boulderdash.cl.cam.ac.uk>2003-01-26 11:30:21 +0000
committerbd240@boulderdash.cl.cam.ac.uk <bd240@boulderdash.cl.cam.ac.uk>2003-01-26 11:30:21 +0000
commit1e776af7cca070828ee0c40eaa4ec036d0a14dc4 (patch)
tree0485c82d5ea3550caccac4e9cc7c883cb783cae8
parent430d2e106d329b19167290281e92d14279051b2f (diff)
parent76858e72974578745ce60257367fd34e21a08c30 (diff)
downloadxen-1e776af7cca070828ee0c40eaa4ec036d0a14dc4.tar.gz
xen-1e776af7cca070828ee0c40eaa4ec036d0a14dc4.tar.bz2
xen-1e776af7cca070828ee0c40eaa4ec036d0a14dc4.zip
bitkeeper revision 1.18 (3e33c6cdMqnqQnkIxpq_9HHmWHAHfA)
Merge boulderdash.cl.cam.ac.uk:/usr/groups/xeno/BK/xeno into boulderdash.cl.cam.ac.uk:/local/scratch/bd240/xeno
-rw-r--r--.rootkeys1
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--xen-2.4.16/arch/i386/mm.c3
-rw-r--r--xen-2.4.16/common/domain.c55
-rw-r--r--xen-2.4.16/common/domain_page.c67
-rw-r--r--xen-2.4.16/common/memory.c141
-rw-r--r--xen-2.4.16/common/page_alloc.c54
-rw-r--r--xen-2.4.16/common/slab.c106
-rw-r--r--xen-2.4.16/include/asm-i386/domain_page.h16
-rw-r--r--xen-2.4.16/include/asm-i386/page.h4
-rw-r--r--xen-2.4.16/include/xeno/slab.h3
-rw-r--r--xen-2.4.16/net/dev.c22
12 files changed, 350 insertions, 123 deletions
diff --git a/.rootkeys b/.rootkeys
index c3c231bbab..126194df93 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -39,6 +39,7 @@
3ddb79bdrqnW93GR9gZk1OJe1qK-iQ xen-2.4.16/common/brlock.c
3ddb79bdLX_P6iB7ILiblRLWvebapg xen-2.4.16/common/dom0_ops.c
3ddb79bdYO5D8Av12NHqPeSviav7cg xen-2.4.16/common/domain.c
+3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen-2.4.16/common/domain_page.c
3ddb79bdeyutmaXEfpQvvxj7eQ0fCw xen-2.4.16/common/event.c
3ddb79bd9drcFPVxd4w2GPOIjLlXpA xen-2.4.16/common/kernel.c
3ddb79bduhSEZI8xa7IbGQCpap5y2A xen-2.4.16/common/lib.c
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index af88da45af..2fd8b201d7 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -1,6 +1,7 @@
akw27@boulderdash.cl.cam.ac.uk
akw27@labyrinth.cl.cam.ac.uk
bd240@boulderdash.cl.cam.ac.uk
+iap10@labyrinth.cl.cam.ac.uk
kaf24@labyrinth.cl.cam.ac.uk
kaf24@plym.cl.cam.ac.uk
kaf24@striker.cl.cam.ac.uk
diff --git a/xen-2.4.16/arch/i386/mm.c b/xen-2.4.16/arch/i386/mm.c
index 2260882efc..29553a9c9b 100644
--- a/xen-2.4.16/arch/i386/mm.c
+++ b/xen-2.4.16/arch/i386/mm.c
@@ -102,7 +102,8 @@ long do_stack_and_ldt_switch(
if ( ldts != current->mm.ldt_sel )
{
- unsigned long *ptabent = GET_GDT_ADDRESS(current);
+ unsigned long *ptabent;
+ ptabent = (unsigned long *)GET_GDT_ADDRESS(current);
/* Out of range for GDT table? */
if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1;
ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */
diff --git a/xen-2.4.16/common/domain.c b/xen-2.4.16/common/domain.c
index 7ccf9501d0..5fefac1747 100644
--- a/xen-2.4.16/common/domain.c
+++ b/xen-2.4.16/common/domain.c
@@ -554,7 +554,7 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params)
unsigned int ft_size = 0;
start_info_t *virt_startinfo_address;
unsigned long long time;
- l2_pgentry_t *l2tab;
+ l2_pgentry_t *l2tab, *l2start;
l1_pgentry_t *l1tab = NULL;
struct pfn_info *page = NULL;
net_ring_t *net_ring;
@@ -609,7 +609,7 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params)
* filled in by now !!
*/
phys_l2tab = ALLOC_FRAME_FROM_DOMAIN();
- l2tab = map_domain_mem(phys_l2tab);
+ l2start = l2tab = map_domain_mem(phys_l2tab);
memcpy(l2tab, idle_pg_table[p->processor], PAGE_SIZE);
l2tab[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
mk_l2_pgentry(__pa(p->mm.perdomain_pt) | __PAGE_HYPERVISOR);
@@ -630,17 +630,16 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params)
if(dom == 0)
ft_size = frame_table_size;
- phys_l2tab += l2_table_offset(virt_load_address)*sizeof(l2_pgentry_t);
+ l2tab += l2_table_offset(virt_load_address);
for ( cur_address = start_address;
cur_address != (end_address + PAGE_SIZE + ft_size);
cur_address += PAGE_SIZE )
{
if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
{
+ if ( l1tab != NULL ) unmap_domain_mem(l1tab-1);
phys_l1tab = ALLOC_FRAME_FROM_DOMAIN();
- l2tab = map_domain_mem(phys_l2tab);
- *l2tab = mk_l2_pgentry(phys_l1tab|L2_PROT);
- phys_l2tab += sizeof(l2_pgentry_t);
+ *l2tab++ = mk_l2_pgentry(phys_l1tab|L2_PROT);
l1tab = map_domain_mem(phys_l1tab);
clear_page(l1tab);
l1tab += l1_table_offset(
@@ -656,43 +655,39 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params)
page->type_count = page->tot_count = 1;
}
}
+ unmap_domain_mem(l1tab-1);
/* Pages that are part of page tables must be read-only. */
vaddr = virt_load_address + alloc_address - start_address;
- phys_l2tab = pagetable_val(p->mm.pagetable) +
- (l2_table_offset(vaddr) * sizeof(l2_pgentry_t));
- l2tab = map_domain_mem(phys_l2tab);
- phys_l1tab = l2_pgentry_to_phys(*l2tab) +
- (l1_table_offset(vaddr) * sizeof(l1_pgentry_t));
- phys_l2tab += sizeof(l2_pgentry_t);
- l1tab = map_domain_mem(phys_l1tab);
+ l2tab = l2start + l2_table_offset(vaddr);
+ l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab));
+ l1tab += l1_table_offset(vaddr);
+ l2tab++;
for ( cur_address = alloc_address;
cur_address != end_address;
cur_address += PAGE_SIZE )
{
- *l1tab++ = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
{
- l2tab = map_domain_mem(phys_l2tab);
- phys_l1tab = l2_pgentry_to_phys(*l2tab);
- phys_l2tab += sizeof(l2_pgentry_t);
- l1tab = map_domain_mem(phys_l1tab);
+ unmap_domain_mem(l1tab-1);
+ l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab));
+ l2tab++;
}
+ *l1tab++ = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
page = frame_table + (cur_address >> PAGE_SHIFT);
page->flags = dom | PGT_l1_page_table;
page->tot_count++;
}
+ unmap_domain_mem(l1tab-1);
page->flags = dom | PGT_l2_page_table;
/* Map in the the shared info structure. */
virt_shinfo_address = end_address - start_address + virt_load_address;
- phys_l2tab = pagetable_val(p->mm.pagetable) +
- (l2_table_offset(virt_shinfo_address) * sizeof(l2_pgentry_t));
- l2tab = map_domain_mem(phys_l2tab);
- phys_l1tab = l2_pgentry_to_phys(*l2tab) +
- (l1_table_offset(virt_shinfo_address) * sizeof(l1_pgentry_t));
- l1tab = map_domain_mem(phys_l1tab);
+ l2tab = l2start + l2_table_offset(virt_shinfo_address);
+ l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab));
+ l1tab += l1_table_offset(virt_shinfo_address);
*l1tab = mk_l1_pgentry(__pa(p->shared_info)|L1_PROT);
+ unmap_domain_mem(l1tab);
/* Set up shared info area. */
rdtscll(time);
@@ -709,13 +704,11 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params)
cur_address < virt_ftable_end_addr;
cur_address += PAGE_SIZE)
{
- phys_l2tab = pagetable_val(p->mm.pagetable) +
- (l2_table_offset(cur_address) * sizeof(l2_pgentry_t));
- l2tab = map_domain_mem(phys_l2tab);
- phys_l1tab = l2_pgentry_to_phys(*l2tab) +
- (l1_table_offset(cur_address) * sizeof(l1_pgentry_t));
- l1tab = map_domain_mem(phys_l1tab);
+ l2tab = l2start + l2_table_offset(cur_address);
+ l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab));
+ l1tab += l1_table_offset(cur_address);
*l1tab = mk_l1_pgentry(__pa(ft_mapping)|L1_PROT);
+ unmap_domain_mem(l1tab);
ft_mapping += PAGE_SIZE;
}
}
@@ -724,6 +717,8 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params)
(alloc_address - start_address - PAGE_SIZE + virt_load_address);
virt_stack_address = (unsigned long)virt_startinfo_address;
+ unmap_domain_mem(l2start);
+
/* Install the new page tables. */
__cli();
__asm__ __volatile__ (
diff --git a/xen-2.4.16/common/domain_page.c b/xen-2.4.16/common/domain_page.c
new file mode 100644
index 0000000000..2e37b72c5c
--- /dev/null
+++ b/xen-2.4.16/common/domain_page.c
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * domain_page.h
+ *
+ * Allow temporary mapping of domain pages. Based on ideas from the
+ * Linux PKMAP code -- the copyrights and credits are retained below.
+ */
+
+/*
+ * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
+ * Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+
+#include <xeno/config.h>
+#include <xeno/sched.h>
+#include <xeno/mm.h>
+#include <asm/domain_page.h>
+#include <asm/pgalloc.h>
+
+static unsigned int map_idx[NR_CPUS];
+
+/* Use a spare PTE bit to mark entries ready for recycling. */
+#define READY_FOR_TLB_FLUSH (1<<10)
+
+static void flush_all_ready_maps(void)
+{
+ unsigned long *cache = mapcache[smp_processor_id()];
+
+ /* A bit skanky -- depends on having an aligned PAGE_SIZE set of PTEs. */
+ do { if ( (*cache & READY_FOR_TLB_FLUSH) ) *cache = 0; }
+ while ( ((unsigned long)(++cache) & ~PAGE_MASK) != 0 );
+
+ local_flush_tlb();
+}
+
+
+void *map_domain_mem(unsigned long pa)
+{
+ unsigned long va;
+ int cpu = smp_processor_id();
+ unsigned int idx;
+ unsigned long *cache = mapcache[cpu];
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ for ( ; ; )
+ {
+ idx = map_idx[cpu] = (map_idx[cpu] + 1) & (MAPCACHE_ENTRIES - 1);
+ if ( idx == 0 ) flush_all_ready_maps();
+ if ( cache[idx] == 0 ) break;
+ }
+
+ cache[idx] = (pa & PAGE_MASK) | PAGE_HYPERVISOR;
+
+ local_irq_restore(flags);
+
+ va = MAPCACHE_VIRT_START + (idx << PAGE_SHIFT) + (pa & ~PAGE_MASK);
+ return (void *)va;
+}
+
+void unmap_domain_mem(void *va)
+{
+ unsigned int idx;
+ idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT;
+ mapcache[smp_processor_id()][idx] |= READY_FOR_TLB_FLUSH;
+}
diff --git a/xen-2.4.16/common/memory.c b/xen-2.4.16/common/memory.c
index 6c8deafff9..fad0768e8b 100644
--- a/xen-2.4.16/common/memory.c
+++ b/xen-2.4.16/common/memory.c
@@ -181,13 +181,17 @@
#define MEM_LOG(_f, _a...) ((void)0)
#endif
+/* Domain 0 is allowed to submit requests on behalf of others. */
+#define DOMAIN_OKAY(_f) \
+ ((((_f) & PG_domain_mask) == current->domain) || (current->domain == 0))
+
/* 'get' checks parameter for validity before inc'ing refcnt. */
static int get_l2_table(unsigned long page_nr);
static int get_l1_table(unsigned long page_nr);
static int get_page(unsigned long page_nr, int writeable);
static int inc_page_refcnt(unsigned long page_nr, unsigned int type);
/* 'put' does no checking because if refcnt not zero, entity must be valid. */
-static int put_l2_table(unsigned long page_nr);
+static void put_l2_table(unsigned long page_nr);
static void put_l1_table(unsigned long page_nr);
static void put_page(unsigned long page_nr, int writeable);
static int dec_page_refcnt(unsigned long page_nr, unsigned int type);
@@ -247,14 +251,14 @@ static int inc_page_refcnt(unsigned long page_nr, unsigned int type)
if ( page_nr >= max_page )
{
MEM_LOG("Page out of range (%08lx>%08lx)", page_nr, max_page);
- return(-1);
+ return -1;
}
page = frame_table + page_nr;
flags = page->flags;
- if ( (flags & PG_domain_mask) != current->domain )
+ if ( !DOMAIN_OKAY(flags) )
{
MEM_LOG("Bad page domain (%ld)", flags & PG_domain_mask);
- return(-1);
+ return -1;
}
if ( (flags & PG_type_mask) != type )
{
@@ -263,13 +267,13 @@ static int inc_page_refcnt(unsigned long page_nr, unsigned int type)
MEM_LOG("Page %08lx bad type/count (%08lx!=%08x) cnt=%ld",
page_nr << PAGE_SHIFT,
flags & PG_type_mask, type, page_type_count(page));
- return(-1);
+ return -1;
}
page->flags |= type;
}
get_page_tot(page);
- return(get_page_type(page));
+ return get_page_type(page);
}
/* Return new refcnt, or -1 on error. */
@@ -281,21 +285,46 @@ static int dec_page_refcnt(unsigned long page_nr, unsigned int type)
if ( page_nr >= max_page )
{
MEM_LOG("Page out of range (%08lx>%08lx)", page_nr, max_page);
- return(-1);
+ return -1;
}
page = frame_table + page_nr;
- if ( (page->flags & (PG_type_mask | PG_domain_mask)) !=
- (type | current->domain) )
+ if ( !DOMAIN_OKAY(page->flags) ||
+ ((page->flags & PG_type_mask) != type) )
{
MEM_LOG("Bad page type/domain (dom=%ld) (type %ld != expected %d)",
page->flags & PG_domain_mask, page->flags & PG_type_mask,
type);
- return(-1);
+ return -1;
}
ASSERT(page_type_count(page) != 0);
if ( (ret = put_page_type(page)) == 0 ) page->flags &= ~PG_type_mask;
put_page_tot(page);
- return(ret);
+ return ret;
+}
+
+
+/* We allow a L2 table to map itself, to achieve a linear pagetable. */
+/* NB. There's no need for a put_twisted_l2_table() function!! */
+static int get_twisted_l2_table(unsigned long entry_pfn, l2_pgentry_t l2e)
+{
+ unsigned long l2v = l2_pgentry_val(l2e);
+
+ /* Clearly the mapping must be read-only :-) */
+ if ( (l2v & _PAGE_RW) )
+ {
+ MEM_LOG("Attempt to install twisted L2 entry with write permissions");
+ return -1;
+ }
+
+ /* This is a sufficient final check. */
+ if ( (l2v >> PAGE_SHIFT) != entry_pfn )
+ {
+ MEM_LOG("L2 tables may not map _other_ L2 tables!\n");
+ return -1;
+ }
+
+ /* We don't bump the reference counts. */
+ return 0;
}
@@ -305,7 +334,7 @@ static int get_l2_table(unsigned long page_nr)
int i, ret=0;
ret = inc_page_refcnt(page_nr, PGT_l2_page_table);
- if ( ret != 0 ) return((ret < 0) ? ret : 0);
+ if ( ret != 0 ) return (ret < 0) ? ret : 0;
/* NEW level-2 page table! Deal with every PDE in the table. */
p_l2_entry = map_domain_mem(page_nr << PAGE_SHIFT);
@@ -317,12 +346,13 @@ static int get_l2_table(unsigned long page_nr)
{
MEM_LOG("Bad L2 page type settings %04lx",
l2_pgentry_val(l2_entry) & (_PAGE_GLOBAL|_PAGE_PSE));
- return(-1);
+ ret = -1;
+ goto out;
}
+ /* Assume we're mapping an L1 table, falling back to twisted L2. */
ret = get_l1_table(l2_pgentry_to_pagenr(l2_entry));
- if ( ret ) return(ret);
- p_l2_entry = map_domain_mem((page_nr << PAGE_SHIFT) +
- ((i+1) * sizeof(l2_pgentry_t)));
+ if ( ret ) ret = get_twisted_l2_table(page_nr, l2_entry);
+ if ( ret ) goto out;
}
/* Now we simply slap in our high mapping. */
@@ -333,7 +363,9 @@ static int get_l2_table(unsigned long page_nr)
DOMAIN_ENTRIES_PER_L2_PAGETABLE] =
mk_l2_pgentry(__pa(current->mm.perdomain_pt) | __PAGE_HYPERVISOR);
- return(ret);
+ out:
+ unmap_domain_mem(p_l2_entry);
+ return ret;
}
static int get_l1_table(unsigned long page_nr)
@@ -343,7 +375,7 @@ static int get_l1_table(unsigned long page_nr)
/* Update ref count for page pointed at by PDE. */
ret = inc_page_refcnt(page_nr, PGT_l1_page_table);
- if ( ret != 0 ) return((ret < 0) ? ret : 0);
+ if ( ret != 0 ) return (ret < 0) ? ret : 0;
/* NEW level-1 page table! Deal with every PTE in the table. */
p_l1_entry = map_domain_mem(page_nr << PAGE_SHIFT);
@@ -357,14 +389,18 @@ static int get_l1_table(unsigned long page_nr)
MEM_LOG("Bad L1 page type settings %04lx",
l1_pgentry_val(l1_entry) &
(_PAGE_GLOBAL|_PAGE_PAT));
- return(-1);
+ ret = -1;
+ goto out;
}
ret = get_page(l1_pgentry_to_pagenr(l1_entry),
l1_pgentry_val(l1_entry) & _PAGE_RW);
- if ( ret ) return(ret);
+ if ( ret ) goto out;
}
- return(ret);
+ out:
+ /* Make sure we unmap the right page! */
+ unmap_domain_mem(p_l1_entry-1);
+ return ret;
}
static int get_page(unsigned long page_nr, int writeable)
@@ -380,7 +416,7 @@ static int get_page(unsigned long page_nr, int writeable)
}
page = frame_table + page_nr;
flags = page->flags;
- if ( (flags & PG_domain_mask) != current->domain )
+ if ( !DOMAIN_OKAY(flags) )
{
MEM_LOG("Bad page domain (%ld)", flags & PG_domain_mask);
return(-1);
@@ -407,28 +443,23 @@ static int get_page(unsigned long page_nr, int writeable)
return(0);
}
-static int put_l2_table(unsigned long page_nr)
+static void put_l2_table(unsigned long page_nr)
{
l2_pgentry_t *p_l2_entry, l2_entry;
- int i, ret;
+ int i;
- ret = dec_page_refcnt(page_nr, PGT_l2_page_table);
- if ( ret != 0 ) return((ret < 0) ? ret : 0);
+ if ( dec_page_refcnt(page_nr, PGT_l2_page_table) ) return;
/* We had last reference to level-2 page table. Free the PDEs. */
p_l2_entry = map_domain_mem(page_nr << PAGE_SHIFT);
- for ( i = 0; i < HYPERVISOR_ENTRIES_PER_L2_PAGETABLE; i++ )
+ for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
{
l2_entry = *p_l2_entry++;
if ( (l2_pgentry_val(l2_entry) & _PAGE_PRESENT) )
- {
put_l1_table(l2_pgentry_to_pagenr(l2_entry));
- p_l2_entry = map_domain_mem((page_nr << PAGE_SHIFT) +
- ((i+1) * sizeof(l2_pgentry_t)));
- }
}
- return(0);
+ unmap_domain_mem(p_l2_entry);
}
static void put_l1_table(unsigned long page_nr)
@@ -436,7 +467,7 @@ static void put_l1_table(unsigned long page_nr)
l1_pgentry_t *p_l1_entry, l1_entry;
int i;
- if ( dec_page_refcnt(page_nr, PGT_l1_page_table) != 0 ) return;
+ if ( dec_page_refcnt(page_nr, PGT_l1_page_table) ) return;
/* We had last reference to level-1 page table. Free the PTEs. */
p_l1_entry = map_domain_mem(page_nr << PAGE_SHIFT);
@@ -449,6 +480,9 @@ static void put_l1_table(unsigned long page_nr)
l1_pgentry_val(l1_entry) & _PAGE_RW);
}
}
+
+ /* Make sure we unmap the right page! */
+ unmap_domain_mem(p_l1_entry-1);
}
static void put_page(unsigned long page_nr, int writeable)
@@ -456,7 +490,7 @@ static void put_page(unsigned long page_nr, int writeable)
struct pfn_info *page;
ASSERT(page_nr < max_page);
page = frame_table + page_nr;
- ASSERT((page->flags & PG_domain_mask) == current->domain);
+ ASSERT(DOMAIN_OKAY(page->flags));
ASSERT((!writeable) ||
((page_type_count(page) != 0) &&
((page->flags & PG_type_mask) == PGT_writeable_page)));
@@ -484,12 +518,6 @@ static int mod_l2_entry(unsigned long pa, l2_pgentry_t new_l2_entry)
goto fail;
}
- /*
- * Write the new value while pointer is still valid. The mapping cache
- * entry for p_l2_entry may get clobbered by {put,get}_l1_table.
- */
- *p_l2_entry = new_l2_entry;
-
if ( (l2_pgentry_val(new_l2_entry) & _PAGE_PRESENT) )
{
if ( (l2_pgentry_val(new_l2_entry) & (_PAGE_GLOBAL|_PAGE_PSE)) )
@@ -508,7 +536,9 @@ static int mod_l2_entry(unsigned long pa, l2_pgentry_t new_l2_entry)
put_l1_table(l2_pgentry_to_pagenr(old_l2_entry));
}
- if ( get_l1_table(l2_pgentry_to_pagenr(new_l2_entry)) )
+ /* Assume we're mapping an L1 table, falling back to twisted L2. */
+ if ( get_l1_table(l2_pgentry_to_pagenr(new_l2_entry)) &&
+ get_twisted_l2_table(pa >> PAGE_SHIFT, new_l2_entry) )
goto fail;
}
}
@@ -517,16 +547,13 @@ static int mod_l2_entry(unsigned long pa, l2_pgentry_t new_l2_entry)
put_l1_table(l2_pgentry_to_pagenr(old_l2_entry));
}
- return(0);
+ *p_l2_entry = new_l2_entry;
+ unmap_domain_mem(p_l2_entry);
+ return 0;
fail:
- /*
- * On failure we put the old value back. We need to regrab the
- * mapping of the physical page frame.
- */
- p_l2_entry = map_domain_mem(pa);
- *p_l2_entry = old_l2_entry;
- return(-1);
+ unmap_domain_mem(p_l2_entry);
+ return -1;
}
@@ -571,12 +598,13 @@ static int mod_l1_entry(unsigned long pa, l1_pgentry_t new_l1_entry)
l1_pgentry_val(old_l1_entry) & _PAGE_RW);
}
- /* p_l1_entry is still valid here */
*p_l1_entry = new_l1_entry;
+ unmap_domain_mem(p_l1_entry);
+ return 0;
- return(0);
fail:
- return(-1);
+ unmap_domain_mem(p_l1_entry);
+ return -1;
}
@@ -614,7 +642,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
break;
case PGEXT_UNPIN_TABLE:
- if ( (page->flags & PG_domain_mask) != current->domain )
+ if ( !DOMAIN_OKAY(page->flags) )
{
err = 1;
MEM_LOG("Page %08lx bad domain (dom=%ld)",
@@ -700,7 +728,7 @@ int do_process_page_updates(page_update_request_t *updates, int count)
case PGREQ_NORMAL:
page = frame_table + pfn;
flags = page->flags;
- if ( (flags & PG_domain_mask) == current->domain )
+ if ( DOMAIN_OKAY(flags) )
{
switch ( (flags & PG_type_mask) )
{
@@ -730,8 +758,9 @@ int do_process_page_updates(page_update_request_t *updates, int count)
flags = page->flags;
if ( (flags | current->domain) == PGT_l1_page_table )
{
-
- *(unsigned long *)map_domain_mem(cur.ptr) = cur.val;
+ unsigned long *va = map_domain_mem(cur.ptr);
+ *va = cur.val;
+ unmap_domain_mem(va);
err = 0;
}
else
diff --git a/xen-2.4.16/common/page_alloc.c b/xen-2.4.16/common/page_alloc.c
index 48966e2acc..1bfeed440f 100644
--- a/xen-2.4.16/common/page_alloc.c
+++ b/xen-2.4.16/common/page_alloc.c
@@ -12,7 +12,7 @@
#include <xeno/lib.h>
#include <asm/page.h>
#include <xeno/spinlock.h>
-
+#include <xeno/slab.h>
static spinlock_t alloc_lock = SPIN_LOCK_UNLOCKED;
@@ -102,7 +102,7 @@ struct chunk_tail_st {
/* Linked lists of free chunks of different powers-of-two in size. */
#define FREELIST_SIZE ((sizeof(void*)<<3)-PAGE_SHIFT)
-static chunk_head_t *free_list[FREELIST_SIZE];
+static chunk_head_t *free_head[FREELIST_SIZE];
static chunk_head_t free_tail[FREELIST_SIZE];
#define FREELIST_EMPTY(_l) ((_l)->next == NULL)
@@ -120,8 +120,8 @@ void __init init_page_allocator(unsigned long min, unsigned long max)
for ( i = 0; i < FREELIST_SIZE; i++ )
{
- free_list[i] = &free_tail[i];
- free_tail[i].pprev = &free_list[i];
+ free_head[i] = &free_tail[i];
+ free_tail[i].pprev = &free_head[i];
free_tail[i].next = NULL;
}
@@ -159,10 +159,10 @@ void __init init_page_allocator(unsigned long min, unsigned long max)
ct = (chunk_tail_t *)min-1;
i -= PAGE_SHIFT;
ch->level = i;
- ch->next = free_list[i];
- ch->pprev = &free_list[i];
+ ch->next = free_head[i];
+ ch->pprev = &free_head[i];
ch->next->pprev = &ch->next;
- free_list[i] = ch;
+ free_head[i] = ch;
ct->level = i;
}
}
@@ -171,29 +171,26 @@ void __init init_page_allocator(unsigned long min, unsigned long max)
/* Allocate 2^@order contiguous pages. */
unsigned long __get_free_pages(int mask, int order)
{
- int i;
+ int i, attempts = 0;
chunk_head_t *alloc_ch, *spare_ch;
chunk_tail_t *spare_ct;
unsigned long flags;
+retry:
spin_lock_irqsave(&alloc_lock, flags);
/* Find smallest order which can satisfy the request. */
for ( i = order; i < FREELIST_SIZE; i++ ) {
- if ( !FREELIST_EMPTY(free_list[i]) )
+ if ( !FREELIST_EMPTY(free_head[i]) )
break;
}
- if ( i == FREELIST_SIZE )
- {
- printk("Cannot handle page request order %d!\n", order);
- return 0;
- }
+ if ( i == FREELIST_SIZE ) goto no_memory;
/* Unlink a chunk. */
- alloc_ch = free_list[i];
- free_list[i] = alloc_ch->next;
+ alloc_ch = free_head[i];
+ free_head[i] = alloc_ch->next;
alloc_ch->next->pprev = alloc_ch->pprev;
/* We may have to break the chunk a number of times. */
@@ -206,13 +203,13 @@ unsigned long __get_free_pages(int mask, int order)
/* Create new header for spare chunk. */
spare_ch->level = i;
- spare_ch->next = free_list[i];
- spare_ch->pprev = &free_list[i];
+ spare_ch->next = free_head[i];
+ spare_ch->pprev = &free_head[i];
spare_ct->level = i;
/* Link in the spare chunk. */
spare_ch->next->pprev = &spare_ch->next;
- free_list[i] = spare_ch;
+ free_head[i] = spare_ch;
}
map_alloc(__pa(alloc_ch)>>PAGE_SHIFT, 1<<order);
@@ -220,6 +217,19 @@ unsigned long __get_free_pages(int mask, int order)
spin_unlock_irqrestore(&alloc_lock, flags);
return((unsigned long)alloc_ch);
+
+ no_memory:
+ if ( attempts++ < 8 )
+ {
+ spin_unlock_irqrestore(&alloc_lock, flags);
+ kmem_cache_reap(0);
+ goto retry;
+ }
+
+ printk("Cannot handle page request order %d!\n", order);
+ dump_slabinfo();
+
+ return 0;
}
@@ -269,10 +279,10 @@ void __free_pages(unsigned long p, int order)
ct = (chunk_tail_t *)(p+size)-1;
ct->level = order;
ch->level = order;
- ch->pprev = &free_list[order];
- ch->next = free_list[order];
+ ch->pprev = &free_head[order];
+ ch->next = free_head[order];
ch->next->pprev = &ch->next;
- free_list[order] = ch;
+ free_head[order] = ch;
spin_unlock_irqrestore(&alloc_lock, flags);
}
diff --git a/xen-2.4.16/common/slab.c b/xen-2.4.16/common/slab.c
index 98a79bb052..3452e89aa7 100644
--- a/xen-2.4.16/common/slab.c
+++ b/xen-2.4.16/common/slab.c
@@ -1837,3 +1837,109 @@ out:
return ret;
}
+void dump_slabinfo()
+{
+ struct list_head *p;
+ unsigned long spin_flags;
+
+ /* Output format version, so at least we can change it without _too_
+ * many complaints.
+ */
+ printk( "slabinfo - version: 1.1"
+#if STATS
+ " (statistics)"
+#endif
+#ifdef CONFIG_SMP
+ " (SMP)"
+#endif
+ "\n");
+ down(&cache_chain_sem);
+ p = &cache_cache.next;
+ do {
+ kmem_cache_t *cachep;
+ struct list_head *q;
+ slab_t *slabp;
+ unsigned long active_objs;
+ unsigned long num_objs;
+ unsigned long active_slabs = 0;
+ unsigned long num_slabs;
+ cachep = list_entry(p, kmem_cache_t, next);
+
+ spin_lock_irq(&cachep->spinlock);
+ active_objs = 0;
+ num_slabs = 0;
+ list_for_each(q,&cachep->slabs_full) {
+ slabp = list_entry(q, slab_t, list);
+ if (slabp->inuse != cachep->num)
+ BUG();
+ active_objs += cachep->num;
+ active_slabs++;
+ }
+ list_for_each(q,&cachep->slabs_partial) {
+ slabp = list_entry(q, slab_t, list);
+ if (slabp->inuse == cachep->num || !slabp->inuse)
+ BUG();
+ active_objs += slabp->inuse;
+ active_slabs++;
+ }
+ list_for_each(q,&cachep->slabs_free) {
+ slabp = list_entry(q, slab_t, list);
+ if (slabp->inuse)
+ BUG();
+ num_slabs++;
+ }
+ num_slabs+=active_slabs;
+ num_objs = num_slabs*cachep->num;
+
+ printk("%-17s %6lu %6lu %6u %4lu %4lu %4u",
+ cachep->name, active_objs, num_objs, cachep->objsize,
+ active_slabs, num_slabs, (1<<cachep->gfporder));
+
+#if STATS
+ {
+ unsigned long errors = cachep->errors;
+ unsigned long high = cachep->high_mark;
+ unsigned long grown = cachep->grown;
+ unsigned long reaped = cachep->reaped;
+ unsigned long allocs = cachep->num_allocations;
+
+ printk(" : %6lu %7lu %5lu %4lu %4lu",
+ high, allocs, grown, reaped, errors);
+ }
+#endif
+#ifdef CONFIG_SMP
+ {
+ unsigned int batchcount = cachep->batchcount;
+ unsigned int limit;
+
+ if (cc_data(cachep))
+ limit = cc_data(cachep)->limit;
+ else
+ limit = 0;
+ printk(" : %4u %4u",
+ limit, batchcount);
+ }
+#endif
+#if STATS && defined(CONFIG_SMP)
+ {
+ unsigned long allochit = atomic_read(&cachep->allochit);
+ unsigned long allocmiss = atomic_read(&cachep->allocmiss);
+ unsigned long freehit = atomic_read(&cachep->freehit);
+ unsigned long freemiss = atomic_read(&cachep->freemiss);
+ printk(" : %6lu %6lu %6lu %6lu",
+ allochit, allocmiss, freehit, freemiss);
+ }
+#endif
+ printk("\n");
+ spin_unlock_irq(&cachep->spinlock);
+
+ p = cachep->next.next;
+ } while (p != &cache_cache.next);
+
+ up(&cache_chain_sem);
+
+ return;
+}
+
+
+
diff --git a/xen-2.4.16/include/asm-i386/domain_page.h b/xen-2.4.16/include/asm-i386/domain_page.h
index a8e4c71013..bae558c377 100644
--- a/xen-2.4.16/include/asm-i386/domain_page.h
+++ b/xen-2.4.16/include/asm-i386/domain_page.h
@@ -9,6 +9,21 @@
extern unsigned long *mapcache[NR_CPUS];
#define MAPCACHE_ENTRIES 1024
+
+/*
+ * Maps a given physical address, returning corresponding virtual address.
+ * The entire page containing that VA is now accessible until a
+ * corresponding call to unmap_domain_mem().
+ */
+extern void *map_domain_mem(unsigned long pa);
+
+/*
+ * Pass a VA within a page previously mapped with map_domain_mem().
+ * That page will then be removed from the mapping lists.
+ */
+extern void unmap_domain_mem(void *va);
+
+#if 0
#define MAPCACHE_HASH(_pfn) ((_pfn) & (MAPCACHE_ENTRIES-1))
static inline void *map_domain_mem(unsigned long pa)
{
@@ -25,3 +40,4 @@ static inline void *map_domain_mem(unsigned long pa)
}
return va;
}
+#endif
diff --git a/xen-2.4.16/include/asm-i386/page.h b/xen-2.4.16/include/asm-i386/page.h
index b6fe406f0c..b0d68a324a 100644
--- a/xen-2.4.16/include/asm-i386/page.h
+++ b/xen-2.4.16/include/asm-i386/page.h
@@ -123,8 +123,8 @@ extern void paging_init(void);
: "memory"); \
} while (0)
-#define __flush_tlb_one(addr) \
-__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+#define __flush_tlb_one(__addr) \
+__asm__ __volatile__("invlpg %0": :"m" (*(char *) (__addr)))
#endif /* !__ASSEMBLY__ */
diff --git a/xen-2.4.16/include/xeno/slab.h b/xen-2.4.16/include/xeno/slab.h
index c7aadff3ea..21a53051f1 100644
--- a/xen-2.4.16/include/xeno/slab.h
+++ b/xen-2.4.16/include/xeno/slab.h
@@ -59,6 +59,9 @@ extern void *kmalloc(size_t, int);
extern void kfree(const void *);
extern int FASTCALL(kmem_cache_reap(int));
+
+extern void dump_slabinfo();
+
#if 0
extern int slabinfo_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data);
diff --git a/xen-2.4.16/net/dev.c b/xen-2.4.16/net/dev.c
index 5c4d999bf3..b99a2e91b4 100644
--- a/xen-2.4.16/net/dev.c
+++ b/xen-2.4.16/net/dev.c
@@ -690,6 +690,7 @@ int netif_rx(struct sk_buff *skb)
int this_cpu = smp_processor_id();
struct softnet_data *queue;
unsigned long flags;
+ net_vif_t *vif;
if (skb->stamp.tv_sec == 0)
get_fast_time(&skb->stamp);
@@ -703,13 +704,13 @@ int netif_rx(struct sk_buff *skb)
netdev_rx_stat[this_cpu].total++;
- if (skb->src_vif == VIF_UNKNOWN_INTERFACE)
+ if ( skb->src_vif == VIF_UNKNOWN_INTERFACE )
skb->src_vif = VIF_PHYSICAL_INTERFACE;
- if (skb->dst_vif == VIF_UNKNOWN_INTERFACE)
+ if ( skb->dst_vif == VIF_UNKNOWN_INTERFACE )
net_get_target_vif(skb);
- if (sys_vif_list[skb->dst_vif] == NULL)
+ if ( (vif = sys_vif_list[skb->dst_vif]) == NULL )
{
// the target vif does not exist.
goto drop;
@@ -730,8 +731,9 @@ int netif_rx(struct sk_buff *skb)
read_lock(&tasklist_lock);
p = &idle0_task;
do {
- if ( p->domain != sys_vif_list[skb->dst_vif]->domain ) continue;
- skb_queue_tail(&sys_vif_list[skb->dst_vif]->skb_list, skb);
+ if ( p->domain != vif->domain ) continue;
+ if ( vif->skb_list.qlen > 100 ) break;
+ skb_queue_tail(&vif->skb_list, skb);
cpu_mask = mark_hyp_event(p, _HYP_EVENT_NET_RX);
read_unlock(&tasklist_lock);
goto found;
@@ -1975,21 +1977,17 @@ long do_net_update(void)
if ( skb != NULL )
{
- skb_get(skb); /* get a reference for non-local delivery */
skb->protocol = eth_type_trans(skb, skb->dev);
skb->src_vif = current_vif->id;
net_get_target_vif(skb);
if ( skb->dst_vif > VIF_PHYSICAL_INTERFACE )
{
- if (netif_rx(skb) == 0)
- /* Give up non-local reference. Packet delivered locally. */
- kfree_skb(skb);
+ (void)netif_rx(skb);
}
else if ( skb->dst_vif == VIF_PHYSICAL_INTERFACE )
{
-
- skb_push(skb, skb->dev->hard_header_len);
- dev_queue_xmit(skb);
+ skb_push(skb, skb->dev->hard_header_len);
+ dev_queue_xmit(skb);
}
else
{