bitkeeper revision 1.656 (3fe4de1f1IOfUVzwLIqE8EHIf7xJoA)

Merge nidd.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into nidd.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk
This commit is contained in:
iap10@nidd.cl.cam.ac.uk committed 2003-12-20 23:41:19 +00:00
commit b2fa5906fc
51 files changed
+1629 -1526

No files matched your search

+1 -2
View File
@@ -79,10 +79,8 @@
3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xc/py/XenoUtil.py
3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py
3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
3f841450eJvqAD1Dldc0_aOweGiglQ xen/GUEST_CHANGES
3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
3e74d2be6ELqhaY1sW0yyHRKhpOvDQ xen/TODO
3ddb79bcZbRBzT3elFWSX7u6NtMagQ xen/arch/i386/Makefile
3ddb79bcBQF85CfLS4i1WGZ4oLLaCA xen/arch/i386/Rules.mk
3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/i386/acpitable.c
@@ -92,6 +90,7 @@
3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/i386/delay.c
3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/i386/entry.S
3ddb79bcY5zW7KhvI9gvfuPi3ZumEg xen/arch/i386/extable.c
3fe443fdDDb0Sw6NQBCk4GQapayfTA xen/arch/i386/flushtlb.c
3ddb79bcesE5E-lS4QhRhlqXxqj9cA xen/arch/i386/i387.c
3ddb79bcCAq6IpdkHueChoVTfXqEQQ xen/arch/i386/i8259.c
3ddb79bcBit4xJXbwtX0kb1hh2uO1Q xen/arch/i386/idle0_task.c
+15 -13
View File
@@ -106,12 +106,12 @@ static int setup_guestos(int xc_handle,
const char *cmdline,
unsigned long shared_info_frame)
{
l1_pgentry_t *vl1tab = NULL, *vl1e = NULL;
l2_pgentry_t *vl2tab = NULL, *vl2e = NULL;
l1_pgentry_t *vl1tab;
l2_pgentry_t *vl2tab;
unsigned long *page_array = NULL;
mmu_update_t *pgt_update_arr = NULL, *pgt_updates = NULL;
int alloc_index, num_pt_pages;
unsigned long l2tab;
unsigned long l2tab, l2e, l1e=0;
unsigned long l1tab = 0;
unsigned long num_pgt_updates = 0;
unsigned long count, pt_start, i, j;
@@ -230,44 +230,46 @@ static int setup_guestos(int xc_handle,
if ( (vl2tab = map_pfn(pm_handle, l2tab >> PAGE_SHIFT)) == NULL )
goto error_out;
memset(vl2tab, 0, PAGE_SIZE);
vl2e = vl2tab + l2_table_offset(virt_load_addr);
unmap_pfn(pm_handle, vl2tab);
l2e = l2tab + (l2_table_offset(virt_load_addr)*sizeof(l2_pgentry_t));
for ( count = 0; count < tot_pages; count++ )
{
if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
if ( (l1e & (PAGE_SIZE-1)) == 0 )
{
l1tab = page_array[alloc_index] << PAGE_SHIFT;
if ( (vl1tab = map_pfn(pm_handle, l1tab >> PAGE_SHIFT)) == NULL )
goto error_out;
memset(vl1tab, 0, PAGE_SIZE);
unmap_pfn(pm_handle, vl1tab);
alloc_index--;
vl1e = vl1tab + l1_table_offset(virt_load_addr +
(count << PAGE_SHIFT));
l1e = l1tab + (l1_table_offset(virt_load_addr+(count<<PAGE_SHIFT))*
sizeof(l1_pgentry_t));
/* make apropriate entry in the page directory */
pgt_updates->ptr = (unsigned long)vl2e;
pgt_updates->ptr = l2e;
pgt_updates->val = l1tab | L2_PROT;
pgt_updates++;
num_pgt_updates++;
vl2e++;
l2e += sizeof(l2_pgentry_t);
}
if ( count < pt_start )
{
pgt_updates->ptr = (unsigned long)vl1e;
pgt_updates->ptr = l1e;
pgt_updates->val = (page_array[count] << PAGE_SHIFT) | L1_PROT;
pgt_updates++;
num_pgt_updates++;
vl1e++;
l1e += sizeof(l1_pgentry_t);
}
else
{
pgt_updates->ptr = (unsigned long)vl1e;
pgt_updates->ptr = l1e;
pgt_updates->val =
((page_array[count] << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW;
pgt_updates++;
num_pgt_updates++;
vl1e++;
l1e += sizeof(l1_pgentry_t);
}
pgt_updates->ptr =
+4 -5
View File
@@ -301,7 +301,8 @@ int xc_linux_restore(int xc_handle,
page[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
}
if ( add_mmu_update(xc_handle, mmu_updates, &mmu_update_idx,
(unsigned long)&ppage[j], page[j]) )
(mfn<<PAGE_SHIFT)+(j*sizeof(l1_pgentry_t)),
page[j]) )
goto out;
}
break;
@@ -337,7 +338,8 @@ int xc_linux_restore(int xc_handle,
page[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
}
if ( add_mmu_update(xc_handle, mmu_updates, &mmu_update_idx,
(unsigned long)&ppage[j], page[j]) )
(mfn<<PAGE_SHIFT)+(j*sizeof(l2_pgentry_t)),
page[j]) )
goto out;
}
break;
@@ -345,9 +347,6 @@ int xc_linux_restore(int xc_handle,
memcpy(ppage, page, PAGE_SIZE);
break;
}
/* NB. Must flush before unmapping page, as pass VAs to Xen. */
if ( flush_mmu_updates(xc_handle, mmu_updates, &mmu_update_idx) )
goto out;
unmap_pfn(pm_handle, ppage);
if ( add_mmu_update(xc_handle, mmu_updates, &mmu_update_idx,
+10 -8
View File
@@ -44,19 +44,20 @@ static int check_pfn_ownership(int xc_handle,
{
dom0_op_t op;
op.cmd = DOM0_GETPAGEFRAMEINFO;
op.u.getpageframeinfo.pfn = mfn;
if ( (do_dom0_op(xc_handle, &op) < 0) ||
(op.u.getpageframeinfo.domain != dom) )
return 0;
return 1;
op.u.getpageframeinfo.pfn = mfn;
op.u.getpageframeinfo.domain = dom;
return (do_dom0_op(xc_handle, &op) >= 0);
}
#define GETPFN_ERR (~0U)
static unsigned int get_pfn_type(int xc_handle, unsigned long mfn)
static unsigned int get_pfn_type(int xc_handle,
unsigned long mfn,
unsigned int dom)
{
dom0_op_t op;
op.cmd = DOM0_GETPAGEFRAMEINFO;
op.u.getpageframeinfo.pfn = mfn;
op.u.getpageframeinfo.pfn = mfn;
op.u.getpageframeinfo.domain = dom;
if ( do_dom0_op(xc_handle, &op) < 0 )
{
PERROR("Unexpected failure when getting page frame info!");
@@ -259,7 +260,8 @@ int xc_linux_save(int xc_handle,
mfn_to_pfn_table[mfn] = i;
/* Query page type by MFN, but store it by PFN. */
if ( (pfn_type[i] = get_pfn_type(xc_handle, mfn)) == GETPFN_ERR )
if ( (pfn_type[i] = get_pfn_type(xc_handle, mfn, domid)) ==
GETPFN_ERR )
goto out;
}
-26
View File
@@ -1,26 +0,0 @@
The interface between Xen and overlying guest OSes has changed in the
following ways since version 1.0:
Modified hypercall 'pt_update'
------------------------------
Page-table updates passed to the 'pt_update' hypercall must now
specify a virtual address that maps the PTE to be modified. Previously
a physical address was used, requiring Xen to temporarily map the PTE
into its own private region so that it could be read and written.
This affects only commands of type PGREQ_NORMAL_UPDATE and
PGREQ_UNCHECKED_UPDATE.
New hypercall 'update_va_mapping'
---------------------------------
A new high-speed page-table update method has been introduced, which
may be of particular benefit when fixing up application page faults.
Invoked as 'update_va_mapping(page_number, new_pte_value, flags)':
<page_number>: The virtual page number in the current address space
whose PTE is to be modified.
<new_pte_value>: The new value to write into the PTE.
<flags>: An ORed combination of
UVMF_INVLPG: Flush stale TLB entry of the updated page mapping
UVMF_FLUSH_TLB: Flush all TLB entries
You can see this new call in use in Xenolinux (common/memory.c).
+1 -1
View File
@@ -2,7 +2,7 @@
# This is the correct place to edit the build version.
# All other places this is stored (eg. compile.h) should be autogenerated.
export XEN_VERSION = 1
export XEN_SUBVERSION = 2
export XEN_SUBVERSION = 3
export XEN_EXTRAVERSION = "-rc"
export BASEDIR := $(shell pwd)
-54
View File
@@ -1,54 +0,0 @@
This is stuff we probably want to implement in the near future.
-- Keir (16/3/03)
1. DOMAIN-0 MANAGEMENT DAEMON
-----------------------------
A better control daemon is required for domain 0, which keeps proper
track of machine resources and can make sensible policy choices. This
may require support in Xen; for example, notifications (eg. DOMn is
killed), and requests (eg. can DOMn allocate x frames of memory?).
2. ASSIGNING DOMAINS TO PROCESSORS
----------------------------------
More intelligent assignment of domains to processors. In
particular, we don't play well with hyperthreading: we will assign
domains to virtual processors on the same package, rather then
spreading them across processor packages.
What we need to do is port code from Linux which stores information on
relationships between processors in the system (eg. which ones are
siblings in the same package). We then use this to balance domains
across packages, and across virtual processors within a package.
3. SANE NETWORK ROUTING
-----------------------
The current virtual firewall/router is completely broken. Needs a new
design and implementation!
Graveyard
*********
The hypervisor page cache
-------------------------
This will allow guest OSes to make use of spare pages in the system, but
allow them to be immediately used for any new domains or memory requests.
The idea is that, when a page is laundered and falls off Linux's clean_LRU
list, rather than freeing it it becomes a candidate for passing down into
the hypervisor. In return, xeno-linux may ask for one of its previously-
cached pages back:
(page, new_id) = cache_query(page, old_id);
If the requested page couldn't be kept, a blank page is returned.
When would Linux make the query? Whenever it wants a page back without
the delay or going to disc. Also, whenever a page would otherwise be
flushed to disc.
To try and add to the cache: (blank_page, new_id) = cache_query(page, NULL);
[NULL means "give me a blank page"].
To try and retrieve from the cache: (page, new_id) = cache_query(x_page, id)
[we may request that x_page just be discarded, and therefore not impinge
on this domain's cache quota].
+1 -1
View File
@@ -47,7 +47,7 @@
#include <asm/hardirq.h>
#include <asm/apic.h>
#include <xeno/mm.h>
#include <asm/io_apic.h>
#include <asm/timex.h>
#include <xeno/ac_timer.h>
#include <xeno/perfc.h>
-1
View File
@@ -82,7 +82,6 @@
#include <xeno/config.h>
#include <xeno/errno.h>
#include <hypervisor-ifs/hypervisor-if.h>
#include <asm/smp.h>
EBX = 0x00
ECX = 0x04
+64
View File
@@ -0,0 +1,64 @@
/******************************************************************************
* flushtlb.c
*
* TLB flushes are timestamped using a global virtual 'clock' which ticks
* on any TLB flush on any processor.
*
* Copyright (c) 2003, K A Fraser
*/
#include <xeno/config.h>
#include <xeno/sched.h>
#include <asm/flushtlb.h>
unsigned long tlbflush_mask;
unsigned long tlbflush_clock;
unsigned long tlbflush_time[NR_CPUS];
static inline void tlb_clocktick(unsigned int cpu)
{
unsigned long x, nx, y, ny;
clear_bit(cpu, &tlbflush_mask);
/* Tick the clock. 'y' contains the current time after the tick. */
ny = tlbflush_clock;
do {
#ifdef CONFIG_SMP
if ( unlikely(((y = ny+1) & (GLOBAL_FLUSH_PERIOD - 1)) == 0) )
{
new_tlbflush_clock_period();
y = tlbflush_clock;
break;
}
#else
y = ny+1;
#endif
}
while ( unlikely((ny = cmpxchg(&tlbflush_clock, y-1, y)) != y-1) );
/* Update cpu's timestamp to current time, unless someone else beats us. */
nx = tlbflush_time[cpu];
do {
if ( unlikely((x = nx) >= y) )
break;
}
while ( unlikely((nx = cmpxchg(&tlbflush_time[cpu], x, y)) != x) );
}
void write_cr3_counted(unsigned long pa)
{
__asm__ __volatile__ (
"movl %0, %%cr3"
: : "r" (pa) : "memory" );
tlb_clocktick(smp_processor_id());
}
void flush_tlb_counted(void)
{
__asm__ __volatile__ (
"movl %%cr3, %%eax; movl %%eax, %%cr3"
: : : "memory", "eax" );
tlb_clocktick(smp_processor_id());
}
+2
View File
@@ -28,6 +28,8 @@
#include <xeno/config.h>
#include <asm/mc146818rtc.h>
#include <asm/io.h>
#include <asm/mpspec.h>
#include <asm/io_apic.h>
#include <asm/smp.h>
#include <asm/desc.h>
#include <asm/smpboot.h>
+16 -58
View File
@@ -15,92 +15,50 @@
#include <asm/pgalloc.h>
#include <asm/page.h>
static unsigned long remap_base = 0;
static unsigned long remap_base = IOREMAP_VIRT_START;
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
static void new_l2e(l2_pgentry_t *pl2e)
{
l1_pgentry_t *pl1e = (l1_pgentry_t *)get_free_page(GFP_KERNEL);
if ( !pl1e ) BUG();
clear_page(pl1e);
*pl2e = mk_l2_pgentry(__pa(pl1e)|__PAGE_HYPERVISOR);
}
void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
void * __ioremap(unsigned long phys_addr,
unsigned long size,
unsigned long flags)
{
unsigned long vaddr;
unsigned long offset, cur=0, last_addr;
l2_pgentry_t *pl2e;
l1_pgentry_t *pl1e;
/* First time through, start allocating from far end of virtual memory. */
if ( !remap_base ) remap_base = IOREMAP_VIRT_START;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
if ( (size == 0) || (last_addr < phys_addr) )
return NULL;
/*
* Don't remap the low PCI/ISA area, it's always mapped..
*/
if (phys_addr >= 0xA0000 && last_addr < 0x100000)
/* Don't remap the low PCI/ISA area: it's always mapped. */
if ( (phys_addr >= 0xA0000) && (last_addr < 0x100000) )
return phys_to_virt(phys_addr);
if(remap_base + size > IOREMAP_VIRT_END-1) {
printk("ioremap: going past end of reserved space!\n");
return NULL;
if ( (remap_base + size) > (IOREMAP_VIRT_END - 1) )
{
printk("ioremap: going past end of reserved space!\n");
return NULL;
}
#if 0
/*
* Don't allow anybody to remap normal RAM that we're using..
*/
if (phys_addr < virt_to_phys(high_memory)) {
char *t_addr, *t_end;
struct pfn_info *page;
t_addr = __va(phys_addr);
t_end = t_addr + (size - 1);
for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
if(!PageReserved(page))
return NULL;
}
#endif
/*
* Mappings have to be page-aligned
*/
/* Mappings have to be page-aligned. */
offset = phys_addr & ~PAGE_MASK;
phys_addr &= PAGE_MASK;
size = PAGE_ALIGN(last_addr) - phys_addr;
/*
* Ok, go for it..
*/
/* Ok, go for it. */
vaddr = remap_base;
remap_base += size;
pl2e = &idle_pg_table[l2_table_offset(vaddr)];
if ( l2_pgentry_empty(*pl2e) ) new_l2e(pl2e);
pl1e = l2_pgentry_to_l1(*pl2e++) + l1_table_offset(vaddr);
for ( ; ; )
{
if ( !l1_pgentry_empty(*pl1e) ) BUG();
do {
*pl1e++ = mk_l1_pgentry((phys_addr+cur)|PAGE_HYPERVISOR|flags);
cur += PAGE_SIZE;
if ( cur == size ) break;
if ( !((unsigned long)pl1e & (PAGE_SIZE-1)) )
{
if ( l2_pgentry_empty(*pl2e) ) new_l2e(pl2e);
pl1e = l2_pgentry_to_l1(*pl2e++);
}
}
while ( (cur += PAGE_SIZE) != size );
flush_tlb_all();
return (void *) (offset + (char *)vaddr);
return (void *)(offset + (char *)vaddr);
}
void iounmap(void *addr)
+2 -1
View File
@@ -24,7 +24,8 @@
#include <xeno/interrupt.h>
#include <xeno/irq.h>
#include <xeno/slab.h>
#include <asm/mpspec.h>
#include <asm/io_apic.h>
#include <asm/msr.h>
#include <asm/hardirq.h>
#include <asm/ptrace.h>
+55 -84
View File
@@ -27,8 +27,8 @@
#include <asm/fixmap.h>
#include <asm/domain_page.h>
static inline void set_pte_phys (unsigned long vaddr,
l1_pgentry_t entry)
static inline void set_pte_phys(unsigned long vaddr,
l1_pgentry_t entry)
{
l2_pgentry_t *l2ent;
l1_pgentry_t *l1ent;
@@ -41,20 +41,22 @@ static inline void set_pte_phys (unsigned long vaddr,
__flush_tlb_one(vaddr);
}
void __set_fixmap (enum fixed_addresses idx,
l1_pgentry_t entry)
void __set_fixmap(enum fixed_addresses idx,
l1_pgentry_t entry)
{
unsigned long address = __fix_to_virt(idx);
if (idx >= __end_of_fixed_addresses) {
if ( likely(idx < __end_of_fixed_addresses) )
set_pte_phys(address, entry);
else
printk("Invalid __set_fixmap\n");
return;
}
set_pte_phys(address, entry);
}
static void __init fixrange_init (unsigned long start,
unsigned long end, l2_pgentry_t *pg_base)
static void __init fixrange_init(unsigned long start,
unsigned long end,
l2_pgentry_t *pg_base)
{
l2_pgentry_t *l2e;
int i;
@@ -66,7 +68,8 @@ static void __init fixrange_init (unsigned long start,
for ( ; (i < ENTRIES_PER_L2_PAGETABLE) && (vaddr != end); l2e++, i++ )
{
if ( !l2_pgentry_empty(*l2e) ) continue;
if ( !l2_pgentry_empty(*l2e) )
continue;
page = (unsigned long)get_free_page(GFP_KERNEL);
clear_page(page);
*l2e = mk_l2_pgentry(__pa(page) | __PAGE_HYPERVISOR);
@@ -79,11 +82,6 @@ void __init paging_init(void)
unsigned long addr;
void *ioremap_pt;
/* XXX initialised in boot.S */
/*if ( cpu_has_pge ) set_in_cr4(X86_CR4_PGE);*/
/*if ( cpu_has_pse ) set_in_cr4(X86_CR4_PSE);*/
/*if ( cpu_has_pae ) set_in_cr4(X86_CR4_PAE);*/
/*
* Fixed mappings, only the page table structure has to be
* created - mappings will be set by set_fixmap():
@@ -115,12 +113,12 @@ void __init paging_init(void)
}
void __init zap_low_mappings (void)
void __init zap_low_mappings(void)
{
int i;
for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
idle_pg_table[i] = mk_l2_pgentry(0);
flush_tlb_all();
flush_tlb_all_pge();
}
@@ -212,86 +210,54 @@ long set_gdt(struct task_struct *p,
unsigned int entries)
{
/* NB. There are 512 8-byte entries per GDT page. */
unsigned int i, j, nr_pages = (entries + 511) / 512;
unsigned long pfn, *gdt_page;
long ret = -EINVAL;
struct pfn_info *page;
int i, nr_pages = (entries + 511) / 512;
unsigned long pfn;
struct desc_struct *vgdt;
spin_lock(&p->page_lock);
/* Check the new GDT. */
for ( i = 0; i < nr_pages; i++ )
{
if ( frames[i] >= max_page )
goto out;
page = frame_table + frames[i];
if ( (page->flags & PG_domain_mask) != p->domain )
goto out;
if ( (page->flags & PG_type_mask) != PGT_gdt_page )
{
if ( page_type_count(page) != 0 )
goto out;
/* Check all potential GDT entries in the page. */
gdt_page = map_domain_mem(frames[0] << PAGE_SHIFT);
for ( j = 0; j < 512; j++ )
if ( !check_descriptor(gdt_page[j*2], gdt_page[j*2+1]) )
goto out;
unmap_domain_mem(gdt_page);
}
}
/* Tear down the old GDT. */
for ( i = 0; i < 16; i++ )
{
pfn = l1_pgentry_to_pagenr(p->mm.perdomain_pt[i]);
p->mm.perdomain_pt[i] = mk_l1_pgentry(0);
if ( pfn == 0 ) continue;
page = frame_table + pfn;
ASSERT((page->flags & PG_type_mask) == PGT_gdt_page);
ASSERT((page->flags & PG_domain_mask) == p->domain);
ASSERT((page_type_count(page) != 0) && (page_tot_count(page) != 0));
put_page_type(page);
put_page_tot(page);
}
/* Install the new GDT. */
for ( i = 0; i < nr_pages; i++ )
{
p->mm.perdomain_pt[i] =
mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
page = frame_table + frames[i];
page->flags &= ~(PG_type_mask | PG_need_flush);
page->flags |= PGT_gdt_page;
get_page_type(page);
get_page_tot(page);
if ( unlikely(frames[i] >= max_page) ||
unlikely(!get_page_and_type(&frame_table[frames[i]],
p, PGT_gdt_page)) )
goto fail;
}
/* Copy reserved GDT entries to the new GDT. */
vgdt = map_domain_mem(frames[i] << PAGE_SHIFT);
vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
gdt_table + FIRST_RESERVED_GDT_ENTRY,
NR_RESERVED_GDT_ENTRIES*8);
unmap_domain_mem(vgdt);
/* Tear down the old GDT. */
for ( i = 0; i < 16; i++ )
{
if ( (pfn = l1_pgentry_to_pagenr(p->mm.perdomain_pt[i])) != 0 )
put_page_and_type(&frame_table[pfn]);
p->mm.perdomain_pt[i] = mk_l1_pgentry(0);
}
/* Install the new GDT. */
for ( i = 0; i < nr_pages; i++ )
p->mm.perdomain_pt[i] =
mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
SET_GDT_ADDRESS(p, GDT_VIRT_START);
SET_GDT_ENTRIES(p, (entries*8)-1);
ret = 0; /* success */
return 0;
out:
spin_unlock(&p->page_lock);
return ret;
fail:
while ( i-- > 0 )
put_page_and_type(&frame_table[frames[i]]);
return -EINVAL;
}
long do_set_gdt(unsigned long *frame_list, unsigned int entries)
{
unsigned int nr_pages = (entries + 511) / 512;
int nr_pages = (entries + 511) / 512;
unsigned long frames[16];
long ret;
@@ -321,14 +287,12 @@ long do_update_descriptor(
if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(word1, word2) )
return -EINVAL;
spin_lock(&current->page_lock);
page = frame_table + pfn;
if ( (page->flags & PG_domain_mask) != current->domain )
page = &frame_table[pfn];
if ( unlikely(!get_page(page, current)) )
goto out;
/* Check if the given frame is in use in an unsafe context. */
switch ( (page->flags & PG_type_mask) )
switch ( page->type_and_flags & PGT_type_mask )
{
case PGT_gdt_page:
/* Disallow updates of Xen-reserved descriptors in the current GDT. */
@@ -336,12 +300,17 @@ long do_update_descriptor(
(((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
(((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
goto out;
if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
goto out;
break;
case PGT_ldt_page:
case PGT_writeable_page:
if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
goto out;
break;
default:
if ( page_type_count(page) != 0 )
if ( unlikely(!get_page_type(page, PGT_writeable_page)) )
goto out;
break;
}
/* All is good so make the update. */
@@ -350,9 +319,11 @@ long do_update_descriptor(
gdt_pent[1] = word2;
unmap_domain_mem(gdt_pent);
put_page_type(page);
ret = 0; /* success */
out:
spin_unlock(&current->page_lock);
put_page(page);
return ret;
}
+1 -2
View File
@@ -6,16 +6,15 @@
#include <linux/config.h>
#include <linux/types.h>
/*#include <linux/kernel.h>*/
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/mpspec.h>
#include <asm/io_apic.h>
#include "pci-i386.h"
+2 -1
View File
@@ -27,6 +27,7 @@
#include <asm/processor.h>
#include <asm/desc.h>
#include <asm/i387.h>
#include <asm/mpspec.h>
#include <xeno/irq.h>
#include <xeno/event.h>
@@ -263,7 +264,7 @@ void switch_to(struct task_struct *prev_p, struct task_struct *next_p)
tss->ss1 = next->ss1;
/* Switch page tables. */
__write_cr3_counted(pagetable_val(next_p->mm.pagetable));
write_cr3_counted(pagetable_val(next_p->mm.pagetable));
set_current(next_p);
+53 -19
View File
@@ -16,6 +16,7 @@
#include <asm/mc146818rtc.h>
#include <asm/pgalloc.h>
#include <asm/smpboot.h>
#include <asm/hardirq.h>
#ifdef CONFIG_SMP
@@ -264,34 +265,67 @@ static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED;
asmlinkage void smp_invalidate_interrupt(void)
{
ack_APIC_irq();
if (test_and_clear_bit(smp_processor_id(), &flush_cpumask))
local_flush_tlb();
clear_bit(smp_processor_id(), &flush_cpumask);
local_flush_tlb();
}
void flush_tlb_others(unsigned long cpumask)
void flush_tlb_mask(unsigned long mask)
{
spin_lock(&tlbstate_lock);
atomic_set_mask(cpumask, &flush_cpumask);
send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
while (flush_cpumask) continue;
if ( unlikely(in_irq()) )
BUG();
if ( mask & (1 << smp_processor_id()) )
{
local_flush_tlb();
mask &= ~(1 << smp_processor_id());
}
if ( mask != 0 )
{
spin_lock(&tlbstate_lock);
flush_cpumask = mask;
send_IPI_mask(mask, INVALIDATE_TLB_VECTOR);
while ( flush_cpumask != 0 )
{
rep_nop();
barrier();
}
spin_unlock(&tlbstate_lock);
}
}
void new_tlbflush_clock_period(void)
{
if ( unlikely(!spin_trylock(&tlbstate_lock)) )
return;
if ( unlikely((flush_cpumask = tlbflush_mask) != 0) )
{
send_IPI_mask(flush_cpumask, INVALIDATE_TLB_VECTOR);
while ( flush_cpumask != 0 )
{
rep_nop();
barrier();
}
}
/* No need for cmpxchg updates here: we are protected by tlbstate lock. */
tlbflush_mask = (1 << smp_num_cpus) - 1;
wmb(); /* Reset the mask before allowing the clock to continue ticking. */
tlbflush_clock++;
spin_unlock(&tlbstate_lock);
}
static inline void do_flush_tlb_all_local(void)
static void flush_tlb_all_pge_ipi(void* info)
{
__flush_tlb_all();
__flush_tlb_pge();
}
static void flush_tlb_all_ipi(void* info)
void flush_tlb_all_pge(void)
{
do_flush_tlb_all_local();
}
void flush_tlb_all(void)
{
smp_call_function (flush_tlb_all_ipi,0,1,1);
do_flush_tlb_all_local();
smp_call_function (flush_tlb_all_pge_ipi,0,1,1);
__flush_tlb_pge();
}
void smp_send_event_check_mask(unsigned long cpu_mask)
+2
View File
@@ -44,6 +44,8 @@
#include <xeno/smp.h>
#include <asm/msr.h>
#include <asm/system.h>
#include <asm/mpspec.h>
#include <asm/io_apic.h>
#include <xeno/sched.h>
#include <xeno/delay.h>
#include <xeno/lib.h>
+3
View File
@@ -211,6 +211,7 @@ static inline void do_trap(int trapnr, char *str,
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
DPRINTK("Trap %d: %08lx -> %08lx\n", trapnr, regs->eip, fixup);
regs->eip = fixup;
regs->xds = regs->xes = regs->xfs = regs->xgs = __HYPERVISOR_DS;
return;
@@ -328,6 +329,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, long error_code)
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
DPRINTK("Page fault: %08lx -> %08lx\n", regs->eip, fixup);
regs->eip = fixup;
regs->xds = regs->xes = regs->xfs = regs->xgs = __HYPERVISOR_DS;
return;
@@ -411,6 +413,7 @@ asmlinkage void do_general_protection(struct pt_regs *regs, long error_code)
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
DPRINTK("GPF (%04lx): %08lx -> %08lx\n", error_code, regs->eip, fixup);
regs->eip = fixup;
regs->xds = regs->xes = regs->xfs = regs->xgs = __HYPERVISOR_DS;
return;
+33 -54
View File
@@ -38,31 +38,6 @@ static unsigned int get_domnr(void)
return 0;
}
static void build_page_list(struct task_struct *p)
{
unsigned long *list;
unsigned long curr;
struct list_head *list_ent;
curr = list_entry(p->pg_head.next, struct pfn_info, list) - frame_table;
list = (unsigned long *)map_domain_mem(curr << PAGE_SHIFT);
list_for_each(list_ent, &p->pg_head)
{
*list++ = list_entry(list_ent, struct pfn_info, list) - frame_table;
if( ((unsigned long)list & ~PAGE_MASK) == 0 )
{
struct list_head *ent = frame_table[curr].list.next;
curr = list_entry(ent, struct pfn_info, list) - frame_table;
unmap_domain_mem(list-1);
list = (unsigned long *)map_domain_mem(curr << PAGE_SHIFT);
}
}
unmap_domain_mem(list);
}
static int msr_cpu_mask;
static unsigned long msr_addr;
static unsigned long msr_lo;
@@ -163,8 +138,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
goto exit_create;
}
build_page_list(p);
ret = p->domain;
op.u.createdomain.domain = ret;
@@ -246,7 +219,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
case DOM0_GETMEMLIST:
{
int i;
struct task_struct * p = find_domain_by_id(op.u.getmemlist.domain);
struct task_struct *p = find_domain_by_id(op.u.getmemlist.domain);
unsigned long max_pfns = op.u.getmemlist.max_pfns;
unsigned long pfn;
unsigned long *buffer = op.u.getmemlist.buffer;
@@ -255,28 +228,27 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
ret = -EINVAL;
if ( p != NULL )
{
list_ent = p->pg_head.next;
pfn = list_entry(list_ent, struct pfn_info, list) - frame_table;
for ( i = 0; (i < max_pfns) && (list_ent != &p->pg_head); i++ )
ret = 0;
spin_lock(&p->page_list_lock);
list_ent = p->page_list.next;
for ( i = 0; (i < max_pfns) && (list_ent != &p->page_list); i++ )
{
pfn = list_entry(list_ent, struct pfn_info, list) -
frame_table;
if ( put_user(pfn, buffer) )
{
ret = -EFAULT;
goto out_getmemlist;
break;
}
buffer++;
list_ent = frame_table[pfn].list.next;
pfn = list_entry(list_ent, struct pfn_info, list) -
frame_table;
}
spin_unlock(&p->page_list_lock);
op.u.getmemlist.num_pfns = i;
copy_to_user(u_dom0_op, &op, sizeof(op));
ret = 0;
out_getmemlist:
put_task_struct(p);
}
}
@@ -369,21 +341,24 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
{
struct pfn_info *page;
unsigned long pfn = op.u.getpageframeinfo.pfn;
if ( pfn >= max_page )
{
ret = -EINVAL;
}
else
{
page = frame_table + pfn;
op.u.getpageframeinfo.domain = page->flags & PG_domain_mask;
op.u.getpageframeinfo.type = NONE;
unsigned int dom = op.u.getpageframeinfo.domain;
struct task_struct *p;
if ( page_type_count(page) != 0 )
ret = -EINVAL;
if ( unlikely(pfn >= max_page) ||
unlikely((p = find_domain_by_id(dom)) == NULL) )
break;
page = &frame_table[pfn];
if ( likely(get_page(page, p)) )
{
op.u.getpageframeinfo.type = NONE;
if ( (page->type_and_flags & PGT_count_mask) != 0 )
{
switch ( page->flags & PG_type_mask )
switch ( page->type_and_flags & PGT_type_mask )
{
case PGT_l1_page_table:
op.u.getpageframeinfo.type = L1TAB;
@@ -393,9 +368,13 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
break;
}
}
copy_to_user(u_dom0_op, &op, sizeof(op));
put_page(page);
}
put_task_struct(p);
copy_to_user(u_dom0_op, &op, sizeof(op));
}
break;
+21 -71
View File
@@ -16,58 +16,26 @@
#include <xeno/event.h>
#include <asm/domain_page.h>
#if 0
#define DPRINTK(_f, _a...) printk( _f , ## _a )
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
static long alloc_dom_mem(struct task_struct *p, reservation_increase_t op)
{
struct list_head *temp;
struct pfn_info *pf; /* pfn_info of current page */
struct pfn_info *page;
unsigned long mpfn; /* machine frame number of current page */
void *va; /* Xen-usable mapping of current page */
unsigned long i;
unsigned long flags;
/*
* POLICY DECISION: Each domain has a page limit.
* NB. The first part of test is because op.size could be so big that
* tot_pages + op.size overflows a u_long.
*/
if( (op.size > p->max_pages) ||
((p->tot_pages + op.size) > p->max_pages) )
return -ENOMEM;
spin_lock_irqsave(&free_list_lock, flags);
if ( free_pfns < (op.size + (SLACK_DOMAIN_MEM_KILOBYTES >>
(PAGE_SHIFT-10))) )
{
spin_unlock_irqrestore(&free_list_lock, flags);
return -ENOMEM;
}
spin_lock(&p->page_lock);
temp = free_list.next;
for ( i = 0; i < op.size; i++ )
{
/* Get a free page and add it to the domain's page list. */
pf = list_entry(temp, struct pfn_info, list);
pf->flags |= p->domain;
set_page_type_count(pf, 0);
set_page_tot_count(pf, 0);
temp = temp->next;
list_del(&pf->list);
list_add_tail(&pf->list, &p->pg_head);
free_pfns--;
p->tot_pages++;
/* Leave some slack pages; e.g., for the network. */
if ( unlikely(free_pfns < (SLACK_DOMAIN_MEM_KILOBYTES >>
(PAGE_SHIFT-10))) )
break;
/* NB. 'alloc_domain_page' does limit checking on pages per domain. */
if ( unlikely((page = alloc_domain_page(p)) == NULL) )
break;
/* Inform the domain of the new page's machine address. */
mpfn = (unsigned long)(pf - frame_table);
mpfn = (unsigned long)(page - frame_table);
copy_to_user(op.pages, &mpfn, sizeof(mpfn));
op.pages++;
@@ -77,26 +45,17 @@ static long alloc_dom_mem(struct task_struct *p, reservation_increase_t op)
unmap_domain_mem(va);
}
spin_unlock(&p->page_lock);
spin_unlock_irqrestore(&free_list_lock, flags);
return op.size;
return i;
}
static long free_dom_mem(struct task_struct *p, reservation_decrease_t op)
{
struct list_head *temp;
struct pfn_info *pf; /* pfn_info of current page */
struct pfn_info *page;
unsigned long mpfn; /* machine frame number of current page */
unsigned long i;
unsigned long flags;
long rc = 0;
int need_flush = 0;
spin_lock_irqsave(&free_list_lock, flags);
spin_lock(&p->page_lock);
temp = free_list.next;
for ( i = 0; i < op.size; i++ )
{
copy_from_user(&mpfn, op.pages, sizeof(mpfn));
@@ -109,37 +68,28 @@ static long free_dom_mem(struct task_struct *p, reservation_decrease_t op)
goto out;
}
pf = &frame_table[mpfn];
if ( (page_type_count(pf) != 0) ||
(page_tot_count(pf) != 0) ||
((pf->flags & PG_domain_mask) != p->domain) )
page = &frame_table[mpfn];
if ( unlikely(!get_page(page, p)) )
{
DPRINTK("Bad page free for domain %d (%ld, %ld, %08lx)\n",
p->domain, page_type_count(pf),
page_tot_count(pf), pf->flags);
DPRINTK("Bad page free for domain %d\n", p->domain);
rc = -EINVAL;
goto out;
}
need_flush |= pf->flags & PG_need_flush;
if ( test_and_clear_bit(_PGC_guest_pinned, &page->count_and_flags) )
put_page_and_type(page);
pf->flags = 0;
if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
put_page(page);
list_del(&pf->list);
list_add(&pf->list, &free_list);
free_pfns++;
p->tot_pages--;
put_page(page);
}
out:
spin_unlock(&p->page_lock);
spin_unlock_irqrestore(&free_list_lock, flags);
if ( need_flush )
{
__flush_tlb();
perfc_incrc(need_flush_tlb_flush);
perfc_incr(need_flush_tlb_flush);
}
return rc ? rc : op.size;
+205 -75
View File
@@ -51,12 +51,11 @@ struct task_struct *do_createdomain(unsigned int dom_id, unsigned int cpu)
sprintf(p->name, "Domain-%d", dom_id);
spin_lock_init(&p->blk_ring_lock);
spin_lock_init(&p->page_lock);
spin_lock_init(&p->event_channel_lock);
p->shared_info = (void *)get_free_page(GFP_KERNEL);
memset(p->shared_info, 0, PAGE_SIZE);
SHARE_PFN_WITH_DOMAIN(virt_to_page(p->shared_info), dom_id);
SHARE_PFN_WITH_DOMAIN(virt_to_page(p->shared_info), p);
p->mm.perdomain_pt = (l1_pgentry_t *)get_free_page(GFP_KERNEL);
memset(p->mm.perdomain_pt, 0, PAGE_SIZE);
@@ -67,8 +66,10 @@ struct task_struct *do_createdomain(unsigned int dom_id, unsigned int cpu)
sched_add_domain(p);
INIT_LIST_HEAD(&p->pg_head);
spin_lock_init(&p->page_list_lock);
INIT_LIST_HEAD(&p->page_list);
p->max_pages = p->tot_pages = 0;
write_lock_irqsave(&tasklist_lock, flags);
SET_LINKS(p);
p->next_hash = task_hash[TASK_HASH(dom_id)];
@@ -218,77 +219,203 @@ long stop_other_domain(unsigned int dom)
return 0;
}
unsigned int alloc_new_dom_mem(struct task_struct *p, unsigned int kbytes)
struct pfn_info *alloc_domain_page(struct task_struct *p)
{
struct list_head *temp;
struct pfn_info *pf;
unsigned int alloc_pfns;
unsigned int req_pages;
unsigned long flags;
/* how many pages do we need to alloc? */
req_pages = kbytes >> (PAGE_SHIFT - 10);
struct pfn_info *page = NULL;
unsigned long flags, mask, pfn_stamp, cpu_stamp;
int i;
spin_lock_irqsave(&free_list_lock, flags);
/* is there enough mem to serve the request? */
if ( (req_pages + (SLACK_DOMAIN_MEM_KILOBYTES >> (PAGE_SHIFT-10))) >
free_pfns )
if ( likely(!list_empty(&free_list)) )
{
spin_unlock_irqrestore(&free_list_lock, flags);
return -1;
page = list_entry(free_list.next, struct pfn_info, list);
list_del(&page->list);
free_pfns--;
}
spin_unlock_irqrestore(&free_list_lock, flags);
if ( unlikely(page == NULL) )
return NULL;
if ( unlikely((mask = page->u.cpu_mask) != 0) )
{
pfn_stamp = page->tlbflush_timestamp;
for ( i = 0; mask != 0; i++ )
{
if ( unlikely(mask & (1<<i)) )
{
cpu_stamp = tlbflush_time[i];
if ( !NEED_FLUSH(cpu_stamp, pfn_stamp) )
mask &= ~(1<<i);
}
}
if ( unlikely(mask != 0) )
{
if ( unlikely(in_irq()) )
{
DPRINTK("Returning NULL from alloc_domain_page: in_irq\n");
goto free_and_exit;
}
perfc_incrc(need_flush_tlb_flush);
flush_tlb_mask(mask);
}
}
/* allocate pages and build a thread through frame_table */
temp = free_list.next;
for ( alloc_pfns = 0; alloc_pfns < req_pages; alloc_pfns++ )
page->u.domain = p;
page->type_and_flags = 0;
if ( p != NULL )
{
pf = list_entry(temp, struct pfn_info, list);
pf->flags = p->domain;
set_page_type_count(pf, 0);
set_page_tot_count(pf, 0);
temp = temp->next;
list_del(&pf->list);
list_add_tail(&pf->list, &p->pg_head);
free_pfns--;
ASSERT(free_pfns != 0);
if ( unlikely(in_irq()) )
BUG();
wmb(); /* Domain pointer must be visible before updating refcnt. */
spin_lock(&p->page_list_lock);
if ( unlikely(p->tot_pages >= p->max_pages) )
{
spin_unlock(&p->page_list_lock);
goto free_and_exit;
}
list_add_tail(&page->list, &p->page_list);
p->tot_pages++;
page->count_and_flags = PGC_allocated | 1;
spin_unlock(&p->page_list_lock);
}
return page;
free_and_exit:
spin_lock_irqsave(&free_list_lock, flags);
list_add(&page->list, &free_list);
free_pfns++;
spin_unlock_irqrestore(&free_list_lock, flags);
p->tot_pages = req_pages;
return NULL;
}
void free_domain_page(struct pfn_info *page)
{
unsigned long flags;
struct task_struct *p = page->u.domain;
if ( unlikely(in_irq()) )
BUG();
if ( likely(!IS_XEN_HEAP_FRAME(page)) )
{
/*
* No race with setting of zombie bit. If it wasn't set before the
* last reference was dropped, then it can't be set now.
*/
page->u.cpu_mask = 0;
if ( !(page->count_and_flags & PGC_zombie) )
{
page->tlbflush_timestamp = tlbflush_clock;
page->u.cpu_mask = 1 << p->processor;
spin_lock(&p->page_list_lock);
list_del(&page->list);
p->tot_pages--;
spin_unlock(&p->page_list_lock);
}
page->count_and_flags = 0;
spin_lock_irqsave(&free_list_lock, flags);
list_add(&page->list, &free_list);
free_pfns++;
spin_unlock_irqrestore(&free_list_lock, flags);
}
else
{
/*
* No need for a TLB flush. Non-domain pages are always co-held by Xen,
* and the Xen reference is not dropped until the domain is dead.
* DOM0 may hold references, but it's trusted so no need to flush.
*/
page->u.cpu_mask = 0;
page->count_and_flags = 0;
free_page((unsigned long)page_to_virt(page));
}
}
void free_all_dom_mem(struct task_struct *p)
{
struct list_head *ent, zombies;
struct pfn_info *page;
INIT_LIST_HEAD(&zombies);
spin_lock(&p->page_list_lock);
while ( (ent = p->page_list.next) != &p->page_list )
{
page = list_entry(ent, struct pfn_info, list);
if ( unlikely(!get_page(page, p)) )
{
/*
* Another CPU has dropped the last reference and is responsible
* for removing the page from this list. Wait for them to do so.
*/
spin_unlock(&p->page_list_lock);
while ( p->page_list.next == ent )
barrier();
spin_lock(&p->page_list_lock);
continue;
}
set_bit(_PGC_zombie, &page->count_and_flags);
list_del(&page->list);
p->tot_pages--;
list_add(&page->list, &zombies);
}
spin_unlock(&p->page_list_lock);
/* We do the potentially complex 'put' operations with no lock held. */
while ( (ent = zombies.next) != &zombies )
{
page = list_entry(ent, struct pfn_info, list);
list_del(&page->list);
if ( test_and_clear_bit(_PGC_guest_pinned, &page->count_and_flags) )
put_page_and_type(page);
if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
put_page(page);
put_page(page);
}
}
unsigned int alloc_new_dom_mem(struct task_struct *p, unsigned int kbytes)
{
unsigned int alloc_pfns, nr_pages;
nr_pages = kbytes >> (PAGE_SHIFT - 10);
/* TEMPORARY: max_pages should be explicitly specified. */
p->max_pages = p->tot_pages;
p->max_pages = nr_pages;
for ( alloc_pfns = 0; alloc_pfns < nr_pages; alloc_pfns++ )
{
if ( unlikely(alloc_domain_page(p) == NULL) ||
unlikely(free_pfns < (SLACK_DOMAIN_MEM_KILOBYTES >>
(PAGE_SHIFT-10))) )
{
free_all_dom_mem(p);
return -1;
}
}
p->tot_pages = nr_pages;
return 0;
}
void free_all_dom_mem(struct task_struct *p)
{
struct list_head *ent;
unsigned long flags;
spin_lock_irqsave(&free_list_lock, flags);
while ( (ent = p->pg_head.next) != &p->pg_head )
{
struct pfn_info *pf = list_entry(ent, struct pfn_info, list);
set_page_type_count(pf, 0);
set_page_tot_count(pf, 0);
pf->flags = 0;
ASSERT(ent->next->prev == ent);
ASSERT(ent->prev->next == ent);
list_del(ent);
list_add(ent, &free_list);
free_pfns++;
}
spin_unlock_irqrestore(&free_list_lock, flags);
p->tot_pages = 0;
}
/* Release resources belonging to task @p. */
void release_task(struct task_struct *p)
{
@@ -309,7 +436,6 @@ void release_task(struct task_struct *p)
destroy_event_channels(p);
free_page((unsigned long)p->mm.perdomain_pt);
UNSHARE_PFN(virt_to_page(p->shared_info));
free_page((unsigned long)p->shared_info);
free_all_dom_mem(p);
kmem_cache_free(task_struct_cachep, p);
@@ -360,11 +486,10 @@ int final_setup_guestos(struct task_struct *p, dom0_builddomain_t *builddomain)
p->failsafe_selector = builddomain->ctxt.failsafe_callback_cs;
p->failsafe_address = builddomain->ctxt.failsafe_callback_eip;
/* NB. Page base must already be pinned! */
phys_l2tab = builddomain->ctxt.pt_base;
p->mm.pagetable = mk_pagetable(phys_l2tab);
get_page_type(&frame_table[phys_l2tab>>PAGE_SHIFT]);
get_page_tot(&frame_table[phys_l2tab>>PAGE_SHIFT]);
get_page_and_type(&frame_table[phys_l2tab>>PAGE_SHIFT], p,
PGT_l2_page_table);
/* Set up the shared info structure. */
update_dom_time(p->shared_info);
@@ -449,7 +574,7 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
return -ENOMEM;
}
alloc_address = list_entry(p->pg_head.prev, struct pfn_info, list) -
alloc_address = list_entry(p->page_list.prev, struct pfn_info, list) -
frame_table;
alloc_address <<= PAGE_SHIFT;
alloc_index = p->tot_pages;
@@ -497,7 +622,7 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
p->mm.pagetable = mk_pagetable(phys_l2tab);
l2tab += l2_table_offset(virt_load_address);
cur_address = list_entry(p->pg_head.next, struct pfn_info, list) -
cur_address = list_entry(p->page_list.next, struct pfn_info, list) -
frame_table;
cur_address <<= PAGE_SHIFT;
for ( count = 0; count < p->tot_pages; count++ )
@@ -514,10 +639,10 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
}
*l1tab++ = mk_l1_pgentry(cur_address|L1_PROT);
page = frame_table + (cur_address >> PAGE_SHIFT);
page->flags = dom | PGT_writeable_page | PG_need_flush;
set_page_type_count(page, 1);
set_page_tot_count(page, 1);
page = &frame_table[cur_address >> PAGE_SHIFT];
set_bit(_PGC_tlb_flush_on_type_change, &page->count_and_flags);
if ( !get_page_and_type(page, p, PGT_writeable_page) )
BUG();
/* Set up the MPT entry. */
machine_to_phys_mapping[cur_address >> PAGE_SHIFT] = count;
@@ -538,8 +663,9 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
{
*l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
page = frame_table + l1_pgentry_to_pagenr(*l1tab);
page->flags = dom | PGT_l1_page_table;
get_page_tot(page);
page->type_and_flags &= ~PGT_type_mask;
page->type_and_flags |= PGT_l1_page_table;
get_page(page, p); /* an extra ref because of readable mapping */
l1tab++;
if( !((unsigned long)l1tab & (PAGE_SIZE - 1)) )
{
@@ -548,9 +674,13 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
l2tab++;
}
}
get_page_type(page); /* guest_pinned */
get_page_tot(page); /* guest_pinned */
page->flags = dom | PG_guest_pinned | PGT_l2_page_table;
/* Rewrite last L1 page to be a L2 page. */
page->type_and_flags &= ~PGT_type_mask;
page->type_and_flags |= PGT_l2_page_table;
/* Get another ref to L2 page so that it can be pinned. */
if ( !get_page_and_type(page, p, PGT_l2_page_table) )
BUG();
set_bit(_PGC_guest_pinned, &page->count_and_flags);
unmap_domain_mem(l1start);
/* Set up shared info area. */
@@ -565,7 +695,7 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
/* Install the new page tables. */
__cli();
__write_cr3_counted(pagetable_val(p->mm.pagetable));
write_cr3_counted(pagetable_val(p->mm.pagetable));
/* Copy the guest OS image. */
src = (char *)(phy_data_start + 12);
@@ -632,7 +762,7 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
/* Reinstate the caller's page tables. */
__write_cr3_counted(pagetable_val(current->mm.pagetable));
write_cr3_counted(pagetable_val(current->mm.pagetable));
__sti();
p->flags |= PF_CONSTRUCTED;
+7
View File
@@ -181,6 +181,13 @@ void cmain (unsigned long magic, multiboot_info_t *mbi)
for ( ; ; ) ;
}
/* The array of pfn_info structures must fit into the reserved area. */
if ( sizeof(struct pfn_info) > 24 )
{
printk("'struct pfn_info' too large to fit in Xen address space!\n");
for ( ; ; ) ;
}
set_current(&idle0_task);
max_page = (mbi->mem_upper+1024) >> (PAGE_SHIFT - 10);
+553 -511
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -90,7 +90,7 @@ net_vif_t *create_net_vif(int domain)
if ( sizeof(net_ring_t) > PAGE_SIZE ) BUG();
new_ring = (net_ring_t *)get_free_page(GFP_KERNEL);
clear_page(new_ring);
SHARE_PFN_WITH_DOMAIN(virt_to_page(new_ring), domain);
SHARE_PFN_WITH_DOMAIN(virt_to_page(new_ring), p);
/*
* Fill in the new vif struct. Note that, while the vif's refcnt is
+3 -4
View File
@@ -188,12 +188,12 @@ void __init init_page_allocator(unsigned long min, unsigned long max)
/* Release a PHYSICAL address range to the allocator. */
void release_bytes_to_allocator(unsigned long min, unsigned long max)
{
min = round_pgup (min) + PAGE_OFFSET;
max = round_pgdown(max) + PAGE_OFFSET;
min = round_pgup (min);
max = round_pgdown(max);
while ( min < max )
{
__free_pages(min, 0);
__free_pages(min+PAGE_OFFSET, 0);
min += PAGE_SIZE;
}
}
@@ -210,7 +210,6 @@ unsigned long __get_free_pages(int mask, int order)
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_head[i]) )
-18
View File
@@ -14,31 +14,15 @@
#include <xeno/types.h>
#include <xeno/lib.h>
#include <xeno/sched.h>
/*#include <xeno/kernel_stat.h>*/
#include <xeno/errno.h>
/*#include <xeno/locks.h>*/
#include <xeno/mm.h>
/*#include <xeno/swap.h>*/
#include <xeno/init.h>
/*#include <xeno/smp_lock.h>*/
/*#include <xeno/completion.h>*/
#include <asm/system.h>
#include <asm/io.h>
#include <xeno/blk.h>
/*#include <xeno/highmem.h>*/
#include <xeno/slab.h>
#include <xeno/module.h>
/*
* KAF: We can turn off noise relating to barking guest-OS requests.
*/
#if 0
#define DPRINTK(_f, _a...) printk(_f , ## _a)
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
/* This will die as all synchronous stuff is coming to an end */
#if 0
#define complete(_r) panic("completion.h stuff may be needed...")
@@ -47,8 +31,6 @@
#define complete(_r) (*(int *)(_r) = 0)
#endif
/*
* MAC Floppy IWM hooks
*/
+39 -96
View File
@@ -20,12 +20,6 @@
#include <xeno/vbd.h>
#include <xeno/slab.h>
#if 0
#define DPRINTK(_f, _a...) printk( _f , ## _a )
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
/*
* These are rather arbitrary. They are fairly large because adjacent
* requests pulled from a communication ring are quite likely to end
@@ -60,15 +54,11 @@ static atomic_t nr_pending;
static struct buffer_head *completed_bhs[NR_CPUS] __cacheline_aligned;
static int __buffer_is_valid(struct task_struct *p,
unsigned long buffer,
unsigned short size,
int writeable_buffer);
static void __lock_buffer(unsigned long buffer,
unsigned short size,
int writeable_buffer);
static void unlock_buffer(struct task_struct *p,
unsigned long buffer,
static int lock_buffer(struct task_struct *p,
unsigned long buffer,
unsigned short size,
int writeable_buffer);
static void unlock_buffer(unsigned long buffer,
unsigned short size,
int writeable_buffer);
@@ -185,8 +175,7 @@ static void end_block_io_op_softirq(struct softirq_action *h)
{
pending_req = bh->pending_req;
unlock_buffer(pending_req->domain,
virt_to_phys(bh->b_data),
unlock_buffer(virt_to_phys(bh->b_data),
bh->b_size,
(pending_req->operation==READ));
@@ -321,99 +310,62 @@ long do_block_io_op(block_io_op_t *u_block_io_op)
* DOWNWARD CALLS -- These interface with the block-device layer proper.
*/
static int __buffer_is_valid(struct task_struct *p,
unsigned long buffer,
unsigned short size,
int writeable_buffer)
static int lock_buffer(struct task_struct *p,
unsigned long buffer,
unsigned short size,
int writeable_buffer)
{
unsigned long pfn;
struct pfn_info *page;
int rc = 0;
/* A request may span multiple page frames. Each must be checked. */
for ( pfn = buffer >> PAGE_SHIFT;
pfn < ((buffer + size + PAGE_SIZE - 1) >> PAGE_SHIFT);
pfn++ )
{
/* Each frame must be within bounds of machine memory. */
if ( pfn >= max_page )
if ( unlikely(pfn >= max_page) )
goto fail;
page = &frame_table[pfn];
if ( unlikely(!get_page(page, p)) )
goto fail;
if ( writeable_buffer &&
unlikely(!get_page_type(page, PGT_writeable_page)) )
{
DPRINTK("pfn out of range: %08lx\n", pfn);
goto out;
put_page(page);
goto fail;
}
}
page = frame_table + pfn;
return 1;
/* Each frame must belong to the requesting domain. */
if ( (page->flags & PG_domain_mask) != p->domain )
{
DPRINTK("bad domain: expected %d, got %ld\n",
p->domain, page->flags & PG_domain_mask);
goto out;
}
/* If reading into the frame, the frame must be writeable. */
if ( writeable_buffer &&
((page->flags & PG_type_mask) != PGT_writeable_page) &&
(page_type_count(page) != 0) )
{
DPRINTK("non-writeable page passed for block read\n");
goto out;
}
}
rc = 1;
out:
return rc;
fail:
while ( pfn-- > (buffer >> PAGE_SHIFT) )
{
if ( writeable_buffer )
put_page_type(&frame_table[pfn]);
put_page(&frame_table[pfn]);
}
return 0;
}
static void __lock_buffer(unsigned long buffer,
static void unlock_buffer(unsigned long buffer,
unsigned short size,
int writeable_buffer)
{
unsigned long pfn;
struct pfn_info *page;
unsigned long pfn;
for ( pfn = buffer >> PAGE_SHIFT;
pfn < ((buffer + size + PAGE_SIZE - 1) >> PAGE_SHIFT);
pfn++ )
{
page = frame_table + pfn;
if ( writeable_buffer )
{
if ( page_type_count(page) == 0 )
{
page->flags &= ~PG_type_mask;
/* No need for PG_need_flush here. */
page->flags |= PGT_writeable_page;
}
get_page_type(page);
}
get_page_tot(page);
put_page_type(&frame_table[pfn]);
put_page(&frame_table[pfn]);
}
}
static void unlock_buffer(struct task_struct *p,
unsigned long buffer,
unsigned short size,
int writeable_buffer)
{
unsigned long pfn;
struct pfn_info *page;
spin_lock(&p->page_lock);
for ( pfn = buffer >> PAGE_SHIFT;
pfn < ((buffer + size + PAGE_SIZE - 1) >> PAGE_SHIFT);
pfn++ )
{
page = frame_table + pfn;
if ( writeable_buffer )
put_page_type(page);
put_page_tot(page);
}
spin_unlock(&p->page_lock);
}
static int do_block_io_op_domain(struct task_struct *p, int max_to_do)
{
blk_ring_t *blk_ring = p->blk_ring_base;
@@ -480,8 +432,6 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
int new_segs, nr_psegs = 0;
phys_seg_t phys_seg[MAX_BLK_SEGS * 2];
spin_lock(&p->page_lock);
/* Check that number of segments is sane. */
if ( (req->nr_segments == 0) || (req->nr_segments > MAX_BLK_SEGS) )
{
@@ -506,7 +456,7 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
goto bad_descriptor;
}
if ( !__buffer_is_valid(p, buffer, nr_sects<<9, (operation==READ)) )
if ( !lock_buffer(p, buffer, nr_sects<<9, (operation==READ)) )
{
DPRINTK("invalid buffer\n");
goto bad_descriptor;
@@ -530,6 +480,7 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
req->sector_number + tot_sects,
req->sector_number + tot_sects + nr_sects,
req->device);
unlock_buffer(buffer, nr_sects<<9, (operation==READ));
goto bad_descriptor;
}
@@ -546,12 +497,6 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
if ( nr_psegs >= (MAX_BLK_SEGS*2) ) BUG();
}
/* Lock pages associated with each buffer head. */
for ( i = 0; i < nr_psegs; i++ )
__lock_buffer(phys_seg[i].buffer, phys_seg[i].nr_sects<<9,
(operation==READ));
spin_unlock(&p->page_lock);
atomic_inc(&nr_pending);
pending_req = pending_reqs + pending_ring[pending_cons];
PENDREQ_IDX_INC(pending_cons);
@@ -594,7 +539,6 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
return;
bad_descriptor:
spin_unlock(&p->page_lock);
make_response(p, req->id, req->operation, 1);
}
@@ -670,7 +614,7 @@ void init_blkdev_info(struct task_struct *p)
if ( sizeof(*p->blk_ring_base) > PAGE_SIZE ) BUG();
p->blk_ring_base = (blk_ring_t *)get_free_page(GFP_KERNEL);
clear_page(p->blk_ring_base);
SHARE_PFN_WITH_DOMAIN(virt_to_page(p->blk_ring_base), p->domain);
SHARE_PFN_WITH_DOMAIN(virt_to_page(p->blk_ring_base), p);
p->blkdev_list.next = NULL;
spin_lock_init(&p->vbd_lock);
}
@@ -680,7 +624,6 @@ void destroy_blkdev_info(struct task_struct *p)
{
ASSERT(!__on_blkdev_list(p));
UNSHARE_PFN(virt_to_page(p->blk_ring_base));
free_page((unsigned long)p->blk_ring_base);
destroy_all_vbds(p);
}
+6 -27
View File
@@ -23,13 +23,6 @@
extern int ide_probe_devices(xen_disk_info_t *xdi);
extern int scsi_probe_devices(xen_disk_info_t *xdi);
#if 0
#define DPRINTK(_f, _a...) printk( _f , ## _a )
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
/* XXX SMH: crappy 'hash function' .. fix when care. */
#define HSH(_x) ((_x) & (VBD_HTAB_SZ - 1))
@@ -447,16 +440,9 @@ long vbd_probe(vbd_probe_t *probe)
if ( (probe->domain == VBD_PROBE_ALL) || IS_PRIV(p) )
{
/* Privileged domains always get access to the 'real' devices. */
if ( (ret = ide_probe_devices(&probe->xdi)) != 0 )
{
DPRINTK("vbd_probe: error %d in probing ide devices\n", ret);
if ( ((ret = ide_probe_devices(&probe->xdi)) != 0) ||
((ret = scsi_probe_devices(&probe->xdi)) != 0) )
goto out;
}
if ( (ret = scsi_probe_devices(&probe->xdi)) != 0 )
{
DPRINTK("vbd_probe: error %d in probing scsi devices\n", ret);
goto out;
}
}
if ( probe->domain == VBD_PROBE_ALL )
@@ -469,8 +455,6 @@ long vbd_probe(vbd_probe_t *probe)
{
if( (ret = vbd_probe_devices(&probe->xdi, p)) != 0 )
{
DPRINTK("vbd_probe: error %d in probing virtual devices\n",
ret);
read_unlock_irqrestore(&tasklist_lock, flags);
goto out;
}
@@ -478,17 +462,12 @@ long vbd_probe(vbd_probe_t *probe)
}
read_unlock_irqrestore(&tasklist_lock, flags);
}
else
{
if ( (ret = vbd_probe_devices(&probe->xdi, p)) )
{
DPRINTK("vbd_probe: error %d in probing virtual devices\n", ret);
goto out;
}
}
else if ( (ret = vbd_probe_devices(&probe->xdi, p)) != 0 )
goto out;
out:
if ( ret != 0 )
DPRINTK("vbd_probe: err %ld in probing virtual devices\n", ret);
if ( p != NULL )
put_task_struct(p);
return ret;
+3 -1
View File
@@ -1816,10 +1816,12 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
static void
e1000_tx_timeout(struct net_device *netdev)
{
#if 0
struct e1000_adapter *adapter = netdev->priv;
/* Do the reset outside of interrupt context */
//schedule_work(&adapter->tx_timeout_task);
schedule_work(&adapter->tx_timeout_task);
#endif
e1000_tx_timeout_task(netdev); // XXXX HACK!!! XEN
}
-9
View File
@@ -186,15 +186,6 @@ static __inline__ int atomic_add_negative(int i, atomic_t *v)
return c;
}
/* These are x86-specific, used by some header files */
#define atomic_clear_mask(mask, addr) \
__asm__ __volatile__(LOCK "andl %0,%1" \
: : "r" (~(mask)),"m" (*addr) : "memory")
#define atomic_set_mask(mask, addr) \
__asm__ __volatile__(LOCK "orl %0,%1" \
: : "r" (mask),"m" (*addr) : "memory")
/* Atomic operations are already serializing on x86 */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
+28 -29
View File
@@ -1,40 +1,39 @@
/******************************************************************************
* flushtlb.h
*
* TLB flush macros that count flushes. Counting is used to enforce
* zero-copy safety, particularily for the network code.
*
* akw - Jan 21, 2003
* TLB flushes are timestamped using a global virtual 'clock' which ticks
* on any TLB flush on any processor.
*
* Copyright (c) 2003, K A Fraser
*/
#ifndef __FLUSHTLB_H
#define __FLUSHTLB_H
#ifndef __FLUSHTLB_H__
#define __FLUSHTLB_H__
#include <xeno/smp.h>
#include <asm/atomic.h>
atomic_t tlb_flush_count[NR_CPUS];
/*
* Every GLOBAL_FLUSH_PERIOD ticks of the tlbflush clock, every TLB in the
* system is guaranteed to have been flushed.
*/
#define GLOBAL_FLUSH_PERIOD (1<<16)
#define __write_cr3_counted(__pa) \
do { \
__asm__ __volatile__ ( \
"movl %0, %%cr3;" \
:: "r" (__pa) \
: "memory"); \
atomic_inc(&tlb_flush_count[smp_processor_id()]); \
} while (0)
/*
* '_cpu_stamp' is the current timestamp for the CPU we are testing.
* '_lastuse_stamp' is a timestamp taken when the PFN we are testing was last
* used for a purpose that may have caused the CPU's TLB to become tainted.
*/
#define NEED_FLUSH(_cpu_stamp, _lastuse_stamp) \
(((_cpu_stamp) > (_lastuse_stamp)) || \
(((_lastuse_stamp) - (_cpu_stamp)) > (2*GLOBAL_FLUSH_PERIOD)))
#define __flush_tlb_counted() \
do { \
unsigned int tmpreg; \
\
__asm__ __volatile__( \
"movl %%cr3, %0; # flush TLB \n" \
"movl %0, %%cr3; " \
: "=r" (tmpreg) \
:: "memory"); \
atomic_inc(&tlb_flush_count[smp_processor_id()]); \
} while (0)
extern unsigned long tlbflush_mask;
extern unsigned long tlbflush_clock;
extern unsigned long tlbflush_time[NR_CPUS];
#endif
extern void new_tlbflush_clock_period(void);
extern void write_cr3_counted(unsigned long pa);
extern void flush_tlb_counted(void);
#endif /* __FLUSHTLB_H__ */
+3 -4
View File
@@ -36,10 +36,9 @@ static inline void * phys_to_virt(unsigned long address)
return __va(address);
}
/*
* Change "struct page" to physical address.
*/
#define page_to_phys(page) ((page - frame_table) << PAGE_SHIFT)
#define page_to_pfn(_page) ((unsigned long)((_page) - frame_table))
#define page_to_phys(_page) (page_to_pfn(_page) << PAGE_SHIFT)
#define page_to_virt(_page) phys_to_virt(page_to_phys(_page))
extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+3 -3
View File
@@ -92,7 +92,7 @@ typedef struct { unsigned long pt_lo; } pagetable_t;
extern l2_pgentry_t idle_pg_table[ENTRIES_PER_L2_PAGETABLE];
extern void paging_init(void);
#define __flush_tlb() __flush_tlb_counted()
#define __flush_tlb() flush_tlb_counted()
/* Flush global pages as well. */
@@ -111,10 +111,10 @@ extern void paging_init(void);
} while (0)
#define __flush_tlb_all() \
#define __flush_tlb_pge() \
do { \
__pge_off(); \
__flush_tlb_counted(); \
flush_tlb_counted(); \
__pge_on(); \
} while (0)
+11 -15
View File
@@ -47,28 +47,24 @@
#ifndef CONFIG_SMP
#define flush_tlb() __flush_tlb()
#define flush_tlb_all() __flush_tlb_all()
#define local_flush_tlb() __flush_tlb()
#define flush_tlb_cpu(_cpu) __flush_tlb()
#define flush_tlb() __flush_tlb()
#define flush_tlb_all() __flush_tlb()
#define flush_tlb_all_pge() __flush_tlb_pge()
#define local_flush_tlb() __flush_tlb()
#define flush_tlb_cpu(_cpu) __flush_tlb()
#define flush_tlb_mask(_mask) __flush_tlb()
#else
#include <xeno/smp.h>
extern void flush_tlb_mask(unsigned long mask);
extern void flush_tlb_all_pge(void);
#define flush_tlb() __flush_tlb()
#define flush_tlb_all() flush_tlb_mask((1 << smp_num_cpus) - 1)
#define local_flush_tlb() __flush_tlb()
extern void flush_tlb_all(void);
extern void flush_tlb_others(unsigned long cpumask);
static inline void flush_tlb_cpu(unsigned int cpu)
{
if ( cpu == smp_processor_id() )
__flush_tlb();
else
flush_tlb_others(1<<cpu);
}
#define flush_tlb_cpu(_cpu) flush_tlb_mask(1 << (_cpu))
#endif
+3 -11
View File
@@ -1,15 +1,8 @@
#ifndef __ASM_SMP_H
#define __ASM_SMP_H
#ifndef __ASSEMBLY__
#include <xeno/config.h>
#include <asm/ptrace.h>
#include <asm/fixmap.h>
#include <asm/bitops.h>
#include <asm/mpspec.h>
#include <asm/io_apic.h>
#include <asm/apic.h>
#endif
#ifdef CONFIG_SMP
#define TARGET_CPUS cpu_online_map
@@ -18,8 +11,6 @@
#endif
#ifdef CONFIG_SMP
#ifndef __ASSEMBLY__
/*
* Private routines/data
*/
@@ -74,6 +65,9 @@ extern void smp_store_cpu_info(int id); /* Store per CPU info (like the initial
#define smp_processor_id() (current->processor)
#include <asm/fixmap.h>
#include <asm/apic.h>
static __inline int hard_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
@@ -86,7 +80,5 @@ static __inline int logical_smp_processor_id(void)
return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
}
#endif /* !__ASSEMBLY__ */
#endif
#endif
+2 -3
View File
@@ -1,11 +1,10 @@
#ifndef __ASM_SPINLOCK_H
#define __ASM_SPINLOCK_H
#include <asm/atomic.h>
#include <asm/rwlock.h>
#include <asm/page.h>
#include <xeno/config.h>
#include <xeno/lib.h>
#include <asm/atomic.h>
#include <asm/rwlock.h>
#if 0
#define SPINLOCK_DEBUG 1
+28 -1
View File
@@ -93,7 +93,34 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#define cmpxchg(ptr,o,n)\
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
(unsigned long)(n),sizeof(*(ptr))))
/*
* This function causes longword _o to be changed to _n at location _p.
* If this access causes a fault then we return 1, otherwise we return 0.
* If no fault occurs then _o is updated to teh value we saw at _p. If this
* is the same as the initial value of _o then _n is written to location _p.
*/
#define cmpxchg_user(_p,_o,_n) \
({ \
int _rc; \
__asm__ __volatile__ ( \
"1: " LOCK_PREFIX "cmpxchgl %2,%3\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movl $1,%1\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 1b,3b\n" \
".previous" \
: "=a" (_o), "=r" (_rc) \
: "q" (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \
: "memory"); \
_rc; \
})
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
+1 -1
View File
@@ -141,8 +141,8 @@ typedef struct dom0_getpageframeinfo_st
{
/* IN variables. */
unsigned long pfn; /* Machine page frame number to query. */
/* OUT variables. */
unsigned int domain; /* To which domain does the frame belong? */
/* OUT variables. */
enum { NONE, L1TAB, L2TAB } type; /* Is the page PINNED to a type? */
} dom0_getpageframeinfo_t;
+2 -2
View File
@@ -125,9 +125,9 @@
* which shifts the least bits out.
*/
/* A normal page-table update request. */
#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is VA. */
#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
/* DOM0 can make entirely unchecked updates which do not affect refcnts. */
#define MMU_UNCHECKED_PT_UPDATE 1 /* unchecked '*ptr = val'. ptr is VA. */
#define MMU_UNCHECKED_PT_UPDATE 1 /* unchecked '*ptr = val'. ptr is MA. */
/* Update an entry in the machine->physical mapping table. */
#define MMU_MACHPHYS_UPDATE 2 /* ptr = MA of frame to modify entry for */
/* An extended command. */
+7
View File
@@ -145,6 +145,13 @@
#define capable(_c) 0
#ifndef NDEBUG
#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \
__FILE__, __LINE__, ## _a)
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
#ifndef __ASSEMBLY__
#include <xeno/compiler.h>
+255 -95
View File
@@ -3,34 +3,35 @@
#define __XENO_MM_H__
#include <xeno/config.h>
#include <xeno/list.h>
#include <xeno/spinlock.h>
#include <xeno/perfc.h>
#include <xeno/sched.h>
#include <asm/pgalloc.h>
#include <asm/atomic.h>
#include <asm/desc.h>
#include <xeno/list.h>
#include <asm/flushtlb.h>
#include <asm/io.h>
#include <hypervisor-ifs/hypervisor-if.h>
#include <xeno/spinlock.h>
/* XXX KAF: These may die eventually, but so many refs in slab.c :((( */
/*
* These are for compatibility with calls to the Linux memory allocators.
*/
/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */
#define __GFP_DMA 0x01
/* Action modifiers - doesn't change the zoning */
#define GFP_DMA __GFP_DMA
#define __GFP_WAIT 0x10 /* Can wait and reschedule? */
#define __GFP_HIGH 0x20 /* Should access emergency pools? */
#define __GFP_IO 0x40 /* Can start low memory physical IO? */
#define __GFP_HIGHIO 0x80 /* Can start high mem physical IO? */
#define __GFP_FS 0x100 /* Can call down to low-level FS? */
#define GFP_ATOMIC (__GFP_HIGH)
#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | \
__GFP_HIGHIO | __GFP_FS)
/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
platforms, used as appropriate on others */
#define GFP_DMA __GFP_DMA
/******************************************************************************
/*
* The following is for page_alloc.c.
*/
@@ -44,95 +45,80 @@ void __free_pages(unsigned long p, int order);
#define free_page(_p) (__free_pages(_p,0))
/******************************************************************************
* The following is the array of page info. One entry per page owned
* by the hypervisor, indexed from `mem_map', just like Linux.
*
* 12.11.02. We no longer use struct page or mem_map, these are replaced
* with struct pfn_info and frame_table respectively. Boris Dragovic
*/
typedef struct pfn_info {
struct list_head list; /* ->mapping has some page lists. */
unsigned long flags; /* atomic flags. */
unsigned long tot_count; /* Total domain usage count. */
unsigned long type_count; /* pagetable/dir, or domain-writeable refs. */
} frame_table_t;
#define get_page_tot(p) ((p)->tot_count++)
#define put_page_tot(p) \
({ ASSERT((p)->tot_count != 0); --(p)->tot_count; })
#define page_tot_count(p) ((p)->tot_count)
#define set_page_tot_count(p,v) ((p)->tot_count = v)
#define get_page_type(p) ((p)->type_count++)
#define put_page_type(p) \
({ ASSERT((p)->type_count != 0); --(p)->type_count; })
#define page_type_count(p) ((p)->type_count)
#define set_page_type_count(p,v) ((p)->type_count = v)
#define PG_domain_mask MAX_DOMAIN_ID /* owning domain (16 bits) */
/* hypervisor flags (domain == 0) */
#define PG_slab 24
/* domain flags (domain != 0) */
/*
* NB. The following page types are MUTUALLY EXCLUSIVE.
* At most one can be true at any point, and 'type_count' counts how many
* references exist of the current type. A change in type can only occur
* when type_count == 0.
* Per-page-frame information.
*/
#define PG_type_mask (15<<24) /* bits 24-27 */
#define PGT_none (0<<24) /* no special uses of this page */
#define PGT_l1_page_table (1<<24) /* using this page as an L1 page table? */
#define PGT_l2_page_table (2<<24) /* using this page as an L2 page table? */
#define PGT_l3_page_table (3<<24) /* using this page as an L3 page table? */
#define PGT_l4_page_table (4<<24) /* using this page as an L4 page table? */
#define PGT_gdt_page (5<<24) /* using this page in a GDT? */
#define PGT_ldt_page (6<<24) /* using this page in an LDT? */
#define PGT_writeable_page (7<<24) /* has writable mappings of this page? */
/*
* This bit indicates that the TLB must be flushed when the type count of this
* frame drops to zero. This is needed on current x86 processors only for
* frames which have guestos-accessible writeable mappings. In this case we
* must prevent stale TLB entries allowing the frame to be written if it used
* for a page table, for example.
*
* We have this bit because the writeable type is actually also used to pin a
* page when it is used as a disk read buffer. This doesn't require a TLB flush
* because the frame never has a mapping in the TLB.
*/
#define PG_need_flush (1<<28)
struct pfn_info
{
/* Each frame can be threaded onto a doubly-linked list. */
struct list_head list;
/* The following possible uses are context-dependent. */
union {
/* Page is in use and not a zombie: we keep a pointer to its owner. */
struct task_struct *domain;
/* Page is not currently allocated: mask of possibly-tainted TLBs. */
unsigned long cpu_mask;
/* Page is a zombie: this word currently has no use. */
unsigned long _unused;
} u;
/* Reference count and various PGC_xxx flags and fields. */
unsigned long count_and_flags;
/* Type reference count and various PGT_xxx flags and fields. */
unsigned long type_and_flags;
/* Timestamp from 'TLB clock', used to reduce need for safety flushes. */
unsigned long tlbflush_timestamp;
};
/*
* This bit indicates that the guest OS has pinned the page to its current
* type. For page tables this can avoid the frame scanning and reference-count
* updates that occur when the type count falls to zero.
*/
#define PG_guest_pinned (1<<29)
/* The following page types are MUTUALLY EXCLUSIVE. */
#define PGT_none (0<<29) /* no special uses of this page */
#define PGT_l1_page_table (1<<29) /* using this page as an L1 page table? */
#define PGT_l2_page_table (2<<29) /* using this page as an L2 page table? */
#define PGT_l3_page_table (3<<29) /* using this page as an L3 page table? */
#define PGT_l4_page_table (4<<29) /* using this page as an L4 page table? */
#define PGT_gdt_page (5<<29) /* using this page in a GDT? */
#define PGT_ldt_page (6<<29) /* using this page in an LDT? */
#define PGT_writeable_page (7<<29) /* has writable mappings of this page? */
#define PGT_type_mask (7<<29) /* Bits 29-31. */
/* Has this page been validated for use as its current type? */
#define _PGT_validated 28
#define PGT_validated (1<<_PGT_validated)
/* 28-bit count of uses of this frame as its current type. */
#define PGT_count_mask ((1<<28)-1)
#define PageSlab(page) test_bit(PG_slab, &(page)->flags)
#define PageSetSlab(page) set_bit(PG_slab, &(page)->flags)
#define PageClearSlab(page) clear_bit(PG_slab, &(page)->flags)
/* The owner of this page is dead: 'u.domain' is no longer valid. */
#define _PGC_zombie 31
#define PGC_zombie (1<<_PGC_zombie)
/* For safety, force a TLB flush when this page's type changes. */
#define _PGC_tlb_flush_on_type_change 30
#define PGC_tlb_flush_on_type_change (1<<_PGC_tlb_flush_on_type_change)
/* Owning guest has pinned this page to its current type? */
#define _PGC_guest_pinned 29
#define PGC_guest_pinned (1<<_PGC_guest_pinned)
/* Cleared when the owning guest 'frees' this page. */
#define _PGC_allocated 28
#define PGC_allocated (1<<_PGC_allocated)
/* 28-bit count of references to this frame. */
#define PGC_count_mask ((1<<28)-1)
#define SHARE_PFN_WITH_DOMAIN(_pfn, _dom) \
do { \
(_pfn)->flags = (_dom) | PGT_writeable_page | PG_need_flush; \
set_page_tot_count((_pfn), 2); \
set_page_type_count((_pfn), 2); \
/* We trust the slab allocator in slab.c, and our use of it. */
#define PageSlab(page) (1)
#define PageSetSlab(page) ((void)0)
#define PageClearSlab(page) ((void)0)
#define IS_XEN_HEAP_FRAME(_pfn) (page_to_phys(_pfn) < MAX_MONITOR_ADDRESS)
#define SHARE_PFN_WITH_DOMAIN(_pfn, _dom) \
do { \
(_pfn)->u.domain = (_dom); \
wmb(); /* install valid domain ptr before updating refcnt. */ \
(_pfn)->count_and_flags = 1; /* Xen holds a writeable reference */ \
(_pfn)->type_and_flags = PGT_writeable_page | PGT_validated | 1; \
} while ( 0 )
#define UNSHARE_PFN(_pfn) \
do { \
(_pfn)->flags = 0; \
set_page_tot_count((_pfn), 0); \
set_page_type_count((_pfn), 0); \
} while ( 0 )
#define UNSHARE_PFN(_pfn) put_page_and_type(_pfn)
/* The array of struct pfn_info,
* free pfn list and number of free pfns in the free list
*/
extern frame_table_t * frame_table;
extern struct pfn_info *frame_table;
extern unsigned long frame_table_size;
extern struct list_head free_list;
extern spinlock_t free_list_lock;
@@ -140,6 +126,180 @@ extern unsigned int free_pfns;
extern unsigned long max_page;
void init_frametable(unsigned long nr_pages);
struct pfn_info *alloc_domain_page(struct task_struct *p);
void free_domain_page(struct pfn_info *page);
int alloc_page_type(struct pfn_info *page, unsigned int type);
void free_page_type(struct pfn_info *page, unsigned int type);
static inline void put_page(struct pfn_info *page)
{
unsigned long nx, x, y = page->count_and_flags;
do {
x = y;
nx = x - 1;
}
while ( unlikely((y = cmpxchg(&page->count_and_flags, x, nx)) != x) );
if ( unlikely((nx & PGC_count_mask) == 0) )
free_domain_page(page);
}
static inline int get_page(struct pfn_info *page,
struct task_struct *domain)
{
unsigned long x, nx, y = page->count_and_flags;
struct task_struct *p, *np = page->u.domain;
do {
x = y;
nx = x + 1;
p = np;
if ( unlikely((x & PGC_count_mask) == 0) || /* Not allocated? */
unlikely((nx & PGC_count_mask) == 0) || /* Count overflow? */
unlikely(x & PGC_zombie) || /* Zombie? */
unlikely(p != domain) ) /* Wrong owner? */
{
DPRINTK("Error pfn %08lx: ed=%p,sd=%p,caf=%08lx\n",
page_to_pfn(page), domain, p, x);
return 0;
}
__asm__ __volatile__(
LOCK_PREFIX "cmpxchg8b %3"
: "=a" (np), "=d" (y), "=b" (p),
"=m" (*(volatile unsigned long long *)(&page->u.domain))
: "0" (p), "1" (x), "b" (p), "c" (nx) );
}
while ( unlikely(np != p) || unlikely(y != x) );
return 1;
}
static inline void put_page_type(struct pfn_info *page)
{
unsigned long nx, x, y = page->type_and_flags;
again:
do {
x = y;
nx = x - 1;
if ( unlikely((nx & PGT_count_mask) == 0) )
{
page->tlbflush_timestamp = tlbflush_clock;
if ( unlikely((nx & PGT_type_mask) <= PGT_l4_page_table) &&
likely(nx & PGT_validated) )
{
/*
* Page-table pages must be unvalidated when count is zero. The
* 'free' is safe because the refcnt is non-zero and the
* validated bit is clear => other ops will spin or fail.
*/
if ( unlikely((y = cmpxchg(&page->type_and_flags, x,
x & ~PGT_validated)) != x) )
goto again;
/* We cleared the 'valid bit' so we must do the clear up. */
free_page_type(page, x & PGT_type_mask);
/* Carry on as we were, but with the 'valid bit' now clear. */
x &= ~PGT_validated;
nx &= ~PGT_validated;
}
}
}
while ( unlikely((y = cmpxchg(&page->type_and_flags, x, nx)) != x) );
}
static inline int get_page_type(struct pfn_info *page, unsigned long type)
{
unsigned long nx, x, y = page->type_and_flags;
again:
do {
x = y;
nx = x + 1;
if ( unlikely((nx & PGT_count_mask) == 0) )
{
DPRINTK("Type count overflow on pfn %08lx\n", page_to_pfn(page));
return 0;
}
else if ( unlikely((x & PGT_count_mask) == 0) )
{
if ( (x & PGT_type_mask) != type )
{
nx &= ~(PGT_type_mask | PGT_validated);
nx |= type;
/* No extra validation needed for writeable pages. */
if ( type == PGT_writeable_page )
nx |= PGT_validated;
}
}
else if ( unlikely((x & PGT_type_mask) != type) )
{
DPRINTK("Unexpected type (saw %08lx != exp %08lx) for pfn %08lx\n",
x & PGT_type_mask, type, page_to_pfn(page));
return 0;
}
else if ( unlikely(!(x & PGT_validated)) )
{
/* Someone else is updating validation of this page. Wait... */
while ( (y = page->type_and_flags) != x )
{
rep_nop();
barrier();
}
goto again;
}
}
while ( unlikely((y = cmpxchg(&page->type_and_flags, x, nx)) != x) );
if ( unlikely(!(nx & PGT_validated)) )
{
/* Try to validate page type; drop the new reference on failure. */
if ( unlikely(!alloc_page_type(page, type)) )
{
DPRINTK("Error while validating pfn %08lx for type %08lx\n",
page_to_pfn(page), type);
put_page_type(page);
return 0;
}
set_bit(_PGT_validated, &page->type_and_flags);
}
return 1;
}
static inline void put_page_and_type(struct pfn_info *page)
{
put_page_type(page);
put_page(page);
}
static inline int get_page_and_type(struct pfn_info *page,
struct task_struct *domain,
unsigned int type)
{
int rc = get_page(page, domain);
if ( likely(rc) && unlikely(!get_page_type(page, type)) )
{
put_page(page);
rc = 0;
}
return rc;
}
#define ASSERT_PAGE_IS_TYPE(_p, _t) \
ASSERT(((_p)->type_and_flags & PGT_type_mask) == (_t)); \
ASSERT(((_p)->type_and_flags & PGT_count_mask) != 0)
#define ASSERT_PAGE_IS_DOMAIN(_p, _d) \
ASSERT(((_p)->count_and_flags & PGC_count_mask) != 0); \
ASSERT((_p)->u.domain == (_d))
int check_descriptor(unsigned long a, unsigned long b);
/*
+4 -3
View File
@@ -1,6 +1,6 @@
/*
* xen performance counters
*/
#ifndef __XENO_PERFC_H__
#define __XENO_PERFC_H__
#include <asm/atomic.h>
@@ -53,3 +53,4 @@ extern struct perfcounter_t perfcounters;
#define perfc_addc(x,y) atomic_add((y), &perfcounters.x[smp_processor_id()])
#define perfc_adda(x,y,z) atomic_add((z), &perfcounters.x[y])
#endif /* __XENO_PERFC_H__ */
-1
View File
@@ -12,7 +12,6 @@ PERFCOUNTER( net_hypercalls, "network hypercalls" )
PERFCOUNTER( net_rx_congestion_drop, "net rx congestion drops" )
PERFCOUNTER( net_rx_capacity_drop, "net rx capacity drops" )
PERFCOUNTER( net_rx_delivered, "net rx delivered" )
PERFCOUNTER( net_rx_tlbflush, "net rx tlb flushes" )
PERFCOUNTER( net_tx_transmitted, "net tx transmitted" )
PERFCOUNTER_CPU( domain_page_tlb_flush, "domain page tlb flushes" )
+6 -7
View File
@@ -4,7 +4,6 @@
#include <xeno/config.h>
#include <xeno/types.h>
#include <xeno/spinlock.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include <xeno/smp.h>
#include <asm/processor.h>
@@ -16,7 +15,6 @@
#include <xeno/time.h>
#include <xeno/ac_timer.h>
#include <xeno/delay.h>
#include <xeno/slab.h>
#define MAX_DOMAIN_NAME 16
@@ -94,9 +92,10 @@ struct task_struct
unsigned int domain; /* domain id */
struct list_head pg_head;
unsigned int tot_pages; /* number of pages currently possesed */
unsigned int max_pages; /* max number of pages that can be possesed */
spinlock_t page_list_lock;
struct list_head page_list;
unsigned int tot_pages; /* number of pages currently possesed */
unsigned int max_pages; /* max number of pages that can be possesed */
/* scheduling */
struct list_head run_list;
@@ -132,8 +131,6 @@ struct task_struct
/* VM */
struct mm_struct mm;
/* We need this lock to check page types and frob reference counts. */
spinlock_t page_lock;
mm_segment_t addr_limit;
@@ -194,6 +191,8 @@ extern struct task_struct *idle_task[NR_CPUS];
#define STACK_SIZE PAGE_SIZE
#include <xeno/slab.h>
extern kmem_cache_t *task_struct_cachep;
#define alloc_task_struct() \
((struct task_struct *)kmem_cache_alloc(task_struct_cachep,GFP_KERNEL))
+1 -1
View File
@@ -34,7 +34,7 @@ extern struct net_device *the_dev;
typedef struct rx_shadow_entry_st
{
unsigned short id;
unsigned short flush_count; /* 16 bits should be enough */
unsigned short _pad;
unsigned long pte_ptr;
unsigned long buf_pfn;
} rx_shadow_entry_t;
+153 -166
View File
@@ -39,12 +39,6 @@
#define rtnl_lock() ((void)0)
#define rtnl_unlock() ((void)0)
#if 0
#define DPRINTK(_f, _a...) printk(_f , ## _a)
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
#define TX_RING_INC(_i) (((_i)+1) & (TX_RING_SIZE-1))
#define RX_RING_INC(_i) (((_i)+1) & (RX_RING_SIZE-1))
#define TX_RING_ADD(_i,_j) (((_i)+(_j)) & (TX_RING_SIZE-1))
@@ -54,9 +48,9 @@ struct skb_completion_queues skb_queue[NR_CPUS] __cacheline_aligned;
static int get_tx_bufs(net_vif_t *vif);
static void __make_tx_response(net_vif_t *vif,
unsigned short id,
unsigned char st);
static void make_tx_response(net_vif_t *vif,
unsigned short id,
unsigned char st);
static void make_rx_response(net_vif_t *vif,
unsigned short id,
unsigned short size,
@@ -499,89 +493,69 @@ struct netif_rx_stats netdev_rx_stat[NR_CPUS];
void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
{
rx_shadow_entry_t *rx;
unsigned long *ptep;
unsigned long *ptep, pte;
struct pfn_info *old_page, *new_page, *pte_page;
unsigned int i;
unsigned short size;
unsigned char offset, status = RING_STATUS_OK;
struct task_struct *p = vif->domain;
memcpy(skb->mac.ethernet->h_dest, vif->vmac, ETH_ALEN);
if ( ntohs(skb->mac.ethernet->h_proto) == ETH_P_ARP )
memcpy(skb->nh.raw + 18, vif->vmac, ETH_ALEN);
/*
* Slightly gross: we need the page_lock so that we can do PTE checking.
* However, we take it slightly early so that it can protect the update
* of rx_cons. This saves us from grabbing two locks.
*/
spin_lock(&vif->domain->page_lock);
spin_lock(&vif->rx_lock);
if ( (i = vif->rx_cons) == vif->rx_prod )
{
spin_unlock(&vif->domain->page_lock);
spin_unlock(&vif->rx_lock);
perfc_incr(net_rx_capacity_drop);
return;
}
rx = vif->rx_shadow_ring + i;
rx = &vif->rx_shadow_ring[i];
vif->rx_cons = RX_RING_INC(i);
size = (unsigned short)skb->len;
offset = (unsigned char)((unsigned long)skb->data & ~PAGE_MASK);
/* Release the page-table page. */
pte_page = frame_table + (rx->pte_ptr >> PAGE_SHIFT);
put_page_type(pte_page);
put_page_tot(pte_page);
old_page = frame_table + rx->buf_pfn;
pte_page = &frame_table[rx->pte_ptr >> PAGE_SHIFT];
old_page = &frame_table[rx->buf_pfn];
new_page = skb->pf;
ptep = map_domain_mem(rx->pte_ptr);
if ( (*ptep & _PAGE_PRESENT) )
new_page->u.domain = p;
wmb(); /* make dom ptr visible before updating refcnt. */
spin_lock(&p->page_list_lock);
list_add(&new_page->list, &p->page_list);
new_page->count_and_flags = PGC_allocated | 2;
spin_unlock(&p->page_list_lock);
get_page_type(new_page, PGT_writeable_page);
set_bit(_PGC_tlb_flush_on_type_change, &new_page->count_and_flags);
wmb(); /* Get type count and set flush bit before updating PTE. */
pte = *ptep;
if ( unlikely(pte & _PAGE_PRESENT) ||
unlikely(cmpxchg(ptep, pte,
(pte & ~PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT |
((new_page - frame_table) << PAGE_SHIFT))) != pte )
{
/* Bail out if the PTE has been reused under our feet. */
list_add(&old_page->list, &vif->domain->pg_head);
old_page->flags = vif->domain->domain;
unmap_domain_mem(ptep);
spin_unlock(&vif->domain->page_lock);
status = RING_STATUS_BAD_PAGE;
goto out;
}
/* Give the new page to the domain, marking it writeable. */
set_page_type_count(new_page, 1);
set_page_tot_count(new_page, 1);
new_page->flags = vif->domain->domain | PGT_writeable_page | PG_need_flush;
list_add(&new_page->list, &vif->domain->pg_head);
/* Patch the PTE to map the new page as writeable. */
machine_to_phys_mapping[new_page - frame_table]
= machine_to_phys_mapping[old_page - frame_table];
*ptep = (*ptep & ~PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT |
(((new_page - frame_table) << PAGE_SHIFT) & PAGE_MASK);
= machine_to_phys_mapping[old_page - frame_table];
unmap_domain_mem(ptep);
spin_unlock(&vif->domain->page_lock);
/* Our skbuff now points at the guest's old frame. */
skb->pf = old_page;
/* Updates must happen before releasing the descriptor. */
smp_wmb();
/*
* NB. The remote flush here should be safe, as we hold no locks. The
* network driver that called us should also have no nasty locks.
*/
if ( rx->flush_count == (unsigned short)
atomic_read(&tlb_flush_count[vif->domain->processor]) )
{
perfc_incr(net_rx_tlbflush);
flush_tlb_cpu(vif->domain->processor);
}
perfc_incr(net_rx_delivered);
/* record this so they can be billed */
@@ -589,7 +563,9 @@ void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
vif->total_bytes_received += size;
out:
put_page_and_type(pte_page);
make_rx_response(vif, rx->id, size, status, offset);
spin_unlock(&vif->rx_lock);
}
/**
@@ -785,8 +761,8 @@ static void net_tx_action(unsigned long unused)
skb->mac.raw = skb->data;
skb->guest_id = tx->id;
skb_shinfo(skb)->frags[0].page = frame_table +
(tx->payload >> PAGE_SHIFT);
skb_shinfo(skb)->frags[0].page =
&frame_table[tx->payload >> PAGE_SHIFT];
skb_shinfo(skb)->frags[0].size = tx->size - PKT_PROT_LEN;
skb_shinfo(skb)->frags[0].page_offset = tx->payload & ~PAGE_MASK;
skb_shinfo(skb)->nr_frags = 1;
@@ -856,10 +832,8 @@ static void tx_skb_release(struct sk_buff *skb)
vif = skb->src_vif;
spin_lock(&vif->domain->page_lock);
for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ )
put_page_tot(skb_shinfo(skb)->frags[i].page);
spin_unlock(&vif->domain->page_lock);
put_page(skb_shinfo(skb)->frags[i].page);
if ( skb->skb_type == SKB_NODATA )
kmem_cache_free(net_header_cachep, skb->head);
@@ -867,7 +841,7 @@ static void tx_skb_release(struct sk_buff *skb)
skb_shinfo(skb)->nr_frags = 0;
spin_lock(&vif->tx_lock);
__make_tx_response(vif, skb->guest_id, RING_STATUS_OK);
make_tx_response(vif, skb->guest_id, RING_STATUS_OK);
spin_unlock(&vif->tx_lock);
/*
@@ -1904,7 +1878,7 @@ static int get_tx_bufs(net_vif_t *vif)
if ( (tx.size <= PKT_PROT_LEN) || (tx.size > ETH_FRAME_LEN) )
{
DPRINTK("Bad packet size: %d\n", tx.size);
__make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
continue;
}
@@ -1932,23 +1906,21 @@ static int get_tx_bufs(net_vif_t *vif)
vif->remaining_credit -= tx.size;
/* No crossing a page boundary as the payload mustn't fragment. */
if ( ((tx.addr & ~PAGE_MASK) + tx.size) >= PAGE_SIZE )
if ( unlikely(((tx.addr & ~PAGE_MASK) + tx.size) >= PAGE_SIZE) )
{
DPRINTK("tx.addr: %lx, size: %u, end: %lu\n",
tx.addr, tx.size, (tx.addr &~PAGE_MASK) + tx.size);
__make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
continue;
}
buf_pfn = tx.addr >> PAGE_SHIFT;
buf_page = frame_table + buf_pfn;
spin_lock(&p->page_lock);
if ( (buf_pfn >= max_page) ||
((buf_page->flags & PG_domain_mask) != p->domain) )
if ( unlikely(buf_pfn >= max_page) ||
unlikely(!get_page(buf_page, p)) )
{
DPRINTK("Bad page frame\n");
spin_unlock(&p->page_lock);
__make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
continue;
}
@@ -1958,8 +1930,8 @@ static int get_tx_bufs(net_vif_t *vif)
init_tx_header(vif, g_data, tx.size, the_dev));
if ( protocol == 0 )
{
__make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
goto tx_unmap_and_continue;
make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
goto cleanup_and_continue;
}
target = net_get_target_vif(g_data, tx.size, vif);
@@ -1969,9 +1941,9 @@ static int get_tx_bufs(net_vif_t *vif)
/* Local delivery */
if ( (skb = dev_alloc_skb(ETH_FRAME_LEN + 32)) == NULL )
{
__make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
make_tx_response(vif, tx.id, RING_STATUS_BAD_PAGE);
put_vif(target);
goto tx_unmap_and_continue;
goto cleanup_and_continue;
}
skb->src_vif = vif;
@@ -1995,7 +1967,7 @@ static int get_tx_bufs(net_vif_t *vif)
if ( netif_rx(skb) == NET_RX_DROP )
kfree_skb(skb);
__make_tx_response(vif, tx.id, RING_STATUS_OK);
make_tx_response(vif, tx.id, RING_STATUS_OK);
}
else if ( (target == VIF_PHYS) || IS_PRIV(p) )
{
@@ -2005,23 +1977,24 @@ static int get_tx_bufs(net_vif_t *vif)
kmem_cache_alloc(net_header_cachep, GFP_KERNEL);
if ( vif->tx_shadow_ring[j].header == NULL )
{
__make_tx_response(vif, tx.id, RING_STATUS_OK);
goto tx_unmap_and_continue;
make_tx_response(vif, tx.id, RING_STATUS_OK);
goto cleanup_and_continue;
}
memcpy(vif->tx_shadow_ring[j].header, g_data, PKT_PROT_LEN);
vif->tx_shadow_ring[j].payload = tx.addr + PKT_PROT_LEN;
get_page_tot(buf_page);
buf_page = NULL; /* hand off our page reference */
j = TX_RING_INC(j);
}
else
{
__make_tx_response(vif, tx.id, RING_STATUS_DROPPED);
make_tx_response(vif, tx.id, RING_STATUS_DROPPED);
}
tx_unmap_and_continue:
cleanup_and_continue:
if ( buf_page != NULL )
put_page(buf_page);
unmap_domain_mem(g_data);
spin_unlock(&p->page_lock);
}
/*
@@ -2044,33 +2017,18 @@ static int get_tx_bufs(net_vif_t *vif)
}
static long get_bufs_from_vif(net_vif_t *vif)
static void get_rx_bufs(net_vif_t *vif)
{
net_ring_t *shared_rings;
net_idx_t *shared_idxs;
struct task_struct *p = vif->domain;
net_ring_t *shared_rings = vif->shared_rings;
net_idx_t *shared_idxs = vif->shared_idxs;
unsigned int i, j;
rx_req_entry_t rx;
unsigned long pte_pfn, buf_pfn;
struct pfn_info *pte_page, *buf_page;
struct task_struct *p = vif->domain;
unsigned long *ptep;
unsigned long *ptep, pte;
shared_idxs = vif->shared_idxs;
shared_rings = vif->shared_rings;
/*
* PHASE 1 -- TRANSMIT RING
*/
if ( get_tx_bufs(vif) )
{
add_to_net_schedule_list_tail(vif);
maybe_schedule_tx_action();
}
/*
* PHASE 2 -- RECEIVE RING
*/
spin_lock(&vif->rx_lock);
/*
* Collect up new receive buffers. We collect up to the guest OS's new
@@ -2085,66 +2043,83 @@ static long get_bufs_from_vif(net_vif_t *vif)
{
rx = shared_rings->rx_ring[i].req;
pte_pfn = rx.addr >> PAGE_SHIFT;
pte_page = frame_table + pte_pfn;
pte_pfn = rx.addr >> PAGE_SHIFT;
pte_page = &frame_table[pte_pfn];
spin_lock(&p->page_lock);
if ( (pte_pfn >= max_page) ||
((pte_page->flags & (PG_type_mask | PG_domain_mask)) !=
(PGT_l1_page_table | p->domain)) )
/* The address passed down must be to a valid PTE. */
if ( unlikely(pte_pfn >= max_page) ||
unlikely(!get_page_and_type(pte_page, p, PGT_l1_page_table)) )
{
DPRINTK("Bad page frame for ppte %d,%08lx,%08lx,%08lx\n",
p->domain, pte_pfn, max_page, pte_page->flags);
spin_unlock(&p->page_lock);
p->domain, pte_pfn, max_page, pte_page->type_and_flags);
make_rx_response(vif, rx.id, 0, RING_STATUS_BAD_PAGE, 0);
continue;
}
ptep = map_domain_mem(rx.addr);
if ( !(*ptep & _PAGE_PRESENT) )
pte = *ptep;
/* We must be passed a valid writeable mapping to swizzle. */
if ( unlikely((pte & (_PAGE_PRESENT|_PAGE_RW)) !=
(_PAGE_PRESENT|_PAGE_RW)) ||
unlikely(cmpxchg(ptep, pte, pte & ~_PAGE_PRESENT) != pte) )
{
DPRINTK("Invalid PTE passed down (not present)\n");
DPRINTK("Invalid PTE passed down (not present or changing)\n");
put_page_and_type(pte_page);
make_rx_response(vif, rx.id, 0, RING_STATUS_BAD_PAGE, 0);
goto rx_unmap_and_continue;
}
buf_pfn = *ptep >> PAGE_SHIFT;
buf_page = frame_table + buf_pfn;
buf_pfn = pte >> PAGE_SHIFT;
buf_page = &frame_table[buf_pfn];
if ( ((buf_page->flags & (PG_type_mask | PG_domain_mask)) !=
(PGT_writeable_page | p->domain)) ||
(page_tot_count(buf_page) != 1) )
{
DPRINTK("Need a mapped-once writeable page (%ld/%ld/%08lx)\n",
page_type_count(buf_page), page_tot_count(buf_page),
buf_page->flags);
make_rx_response(vif, rx.id, 0, RING_STATUS_BAD_PAGE, 0);
goto rx_unmap_and_continue;
}
/*
* The pte they passed was good, so take it away from them. We also
* lock down the page-table page, so it doesn't go away.
* The page must belong to the correct domain, and must be mapped
* just once as a writeable page.
*/
get_page_type(pte_page);
get_page_tot(pte_page);
*ptep &= ~_PAGE_PRESENT;
buf_page->flags = 0;
set_page_type_count(buf_page, 0);
set_page_tot_count(buf_page, 0);
list_del(&buf_page->list);
if ( unlikely(buf_page->u.domain != p) ||
unlikely(!test_and_clear_bit(_PGC_allocated,
&buf_page->count_and_flags)) ||
unlikely(cmpxchg(&buf_page->type_and_flags,
PGT_writeable_page|PGT_validated|1,
0) != (PGT_writeable_page|PGT_validated|1)) )
{
DPRINTK("Bad domain or page mapped writeable more than once.\n");
if ( buf_page->u.domain == p )
set_bit(_PGC_allocated, &buf_page->count_and_flags);
if ( unlikely(cmpxchg(ptep, pte & ~_PAGE_PRESENT, pte) !=
(pte & ~_PAGE_PRESENT)) )
put_page_and_type(buf_page);
make_rx_response(vif, rx.id, 0, RING_STATUS_BAD_PAGE, 0);
goto rx_unmap_and_continue;
}
vif->rx_shadow_ring[j].id = rx.id;
vif->rx_shadow_ring[j].pte_ptr = rx.addr;
vif->rx_shadow_ring[j].buf_pfn = buf_pfn;
vif->rx_shadow_ring[j].flush_count = (unsigned short)
atomic_read(&tlb_flush_count[smp_processor_id()]);
/*
* Now ensure that we can take the last references to this page.
* The final count should be 2, because of PGC_allocated.
*/
if ( unlikely(cmpxchg(&buf_page->count_and_flags,
PGC_tlb_flush_on_type_change | 2, 0) !=
(PGC_tlb_flush_on_type_change | 2)) )
{
DPRINTK("Page held more than once\n");
/* Leave the page unmapped at 'ptep'. Stoopid domain! */
make_rx_response(vif, rx.id, 0, RING_STATUS_BAD_PAGE, 0);
goto rx_unmap_and_continue;
}
/* Remove from the domain's allocation list. */
spin_lock(&p->page_list_lock);
list_del(&buf_page->list);
spin_unlock(&p->page_list_lock);
vif->rx_shadow_ring[j].id = rx.id;
vif->rx_shadow_ring[j].pte_ptr = rx.addr;
vif->rx_shadow_ring[j].buf_pfn = buf_pfn;
j = RX_RING_INC(j);
rx_unmap_and_continue:
unmap_domain_mem(ptep);
spin_unlock(&p->page_lock);
}
vif->rx_req_cons = i;
@@ -2155,6 +2130,20 @@ static long get_bufs_from_vif(net_vif_t *vif)
vif->rx_prod = j;
}
spin_unlock(&vif->rx_lock);
}
static long get_bufs_from_vif(net_vif_t *vif)
{
if ( get_tx_bufs(vif) )
{
add_to_net_schedule_list_tail(vif);
maybe_schedule_tx_action();
}
get_rx_bufs(vif);
return 0;
}
@@ -2162,7 +2151,7 @@ static long get_bufs_from_vif(net_vif_t *vif)
long flush_bufs_for_vif(net_vif_t *vif)
{
int i;
unsigned long *pte;
unsigned long *ptep, pte;
struct pfn_info *page;
struct task_struct *p = vif->domain;
rx_shadow_entry_t *rx;
@@ -2170,7 +2159,7 @@ long flush_bufs_for_vif(net_vif_t *vif)
net_idx_t *shared_idxs = vif->shared_idxs;
/* Return any outstanding receive buffers to the guest OS. */
spin_lock(&p->page_lock);
spin_lock(&vif->rx_lock);
for ( i = vif->rx_req_cons;
(i != shared_idxs->rx_req_prod) &&
(((vif->rx_resp_prod-i) & (RX_RING_SIZE-1)) != 1);
@@ -2184,32 +2173,32 @@ long flush_bufs_for_vif(net_vif_t *vif)
{
rx = &vif->rx_shadow_ring[i];
/* Release the page-table page. */
page = frame_table + (rx->pte_ptr >> PAGE_SHIFT);
put_page_type(page);
put_page_tot(page);
/* Give the buffer page back to the domain. */
page = frame_table + rx->buf_pfn;
list_add(&page->list, &p->pg_head);
page->flags = vif->domain->domain;
page = &frame_table[rx->buf_pfn];
spin_lock(&p->page_list_lock);
list_add(&page->list, &p->page_list);
page->count_and_flags = PGC_allocated | 2;
spin_unlock(&p->page_list_lock);
get_page_type(page, PGT_writeable_page);
set_bit(_PGC_tlb_flush_on_type_change, &page->count_and_flags);
wmb();
/* Patch up the PTE if it hasn't changed under our feet. */
pte = map_domain_mem(rx->pte_ptr);
if ( !(*pte & _PAGE_PRESENT) )
{
*pte = (rx->buf_pfn<<PAGE_SHIFT) | (*pte & ~PAGE_MASK) |
_PAGE_RW | _PAGE_PRESENT;
page->flags |= PGT_writeable_page | PG_need_flush;
set_page_type_count(page, 1);
set_page_tot_count(page, 1);
}
unmap_domain_mem(pte);
ptep = map_domain_mem(rx->pte_ptr);
pte = *ptep;
if ( unlikely(pte & _PAGE_PRESENT) ||
unlikely(cmpxchg(ptep, pte, (rx->buf_pfn<<PAGE_SHIFT) |
(pte & ~PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT)
!= pte) )
put_page_and_type(page);
unmap_domain_mem(ptep);
put_page_and_type(&frame_table[rx->pte_ptr >> PAGE_SHIFT]);
make_rx_response(vif, rx->id, 0, RING_STATUS_DROPPED, 0);
}
vif->rx_cons = i;
spin_unlock(&p->page_lock);
spin_unlock(&vif->rx_lock);
/*
* Flush pending transmit buffers. The guest may still have to wait for
@@ -2221,7 +2210,7 @@ long flush_bufs_for_vif(net_vif_t *vif)
(((vif->tx_resp_prod-i) & (TX_RING_SIZE-1)) != 1);
i = TX_RING_INC(i) )
{
__make_tx_response(vif, shared_rings->tx_ring[i].req.id,
make_tx_response(vif, shared_rings->tx_ring[i].req.id,
RING_STATUS_DROPPED);
}
vif->tx_req_cons = i;
@@ -2296,9 +2285,9 @@ long do_net_io_op(netop_t *uop)
}
static void __make_tx_response(net_vif_t *vif,
unsigned short id,
unsigned char st)
static void make_tx_response(net_vif_t *vif,
unsigned short id,
unsigned char st)
{
unsigned int pos;
tx_resp_entry_t *resp;
@@ -2329,7 +2318,6 @@ static void make_rx_response(net_vif_t *vif,
rx_resp_entry_t *resp;
/* Place on the response ring for the relevant domain. */
spin_lock(&vif->rx_lock);
pos = vif->rx_resp_prod;
resp = &vif->shared_rings->rx_ring[pos].resp;
resp->id = id;
@@ -2344,7 +2332,6 @@ static void make_rx_response(net_vif_t *vif,
unsigned long cpu_mask = mark_guest_event(vif->domain, _EVENT_NET);
guest_event_notify(cpu_mask);
}
spin_unlock(&vif->rx_lock);
}
+4 -25
View File
@@ -133,41 +133,20 @@ static __inline__ void skb_head_to_pool(struct sk_buff *skb)
static inline u8 *alloc_skb_data_page(struct sk_buff *skb)
{
struct list_head *list_ptr;
struct pfn_info *pf;
unsigned long flags;
spin_lock_irqsave(&free_list_lock, flags);
if (!free_pfns) return NULL;
list_ptr = free_list.next;
pf = list_entry(list_ptr, struct pfn_info, list);
pf->flags = 0;
list_del(&pf->list);
free_pfns--;
spin_unlock_irqrestore(&free_list_lock, flags);
struct pfn_info *pf;
if ( unlikely((pf = alloc_domain_page(NULL)) == NULL) )
return NULL;
skb->pf = pf;
return (u8 *)((pf - frame_table) << PAGE_SHIFT);
}
static inline void dealloc_skb_data_page(struct sk_buff *skb)
{
struct pfn_info *pf;
struct pfn_info *pf = skb->pf;
unsigned long flags;
pf = skb->pf;
spin_lock_irqsave(&free_list_lock, flags);
pf->flags = 0;
set_page_type_count(pf, 0);
set_page_tot_count(pf, 0);
list_add(&pf->list, &free_list);
free_pfns++;
spin_unlock_irqrestore(&free_list_lock, flags);
}
@@ -40,7 +40,7 @@ static void DEBUG_allow_pt_reads(void)
pte = update_debug_queue[i].ptep;
if ( pte == NULL ) continue;
update_debug_queue[i].ptep = NULL;
update.ptr = pte;
update.ptr = virt_to_machine(pte);
update.val = update_debug_queue[i].pteval;
HYPERVISOR_mmu_update(&update, 1);
}
@@ -59,7 +59,7 @@ static void DEBUG_disallow_pt_read(unsigned long va)
pgd = pgd_offset_k(va);
pmd = pmd_offset(pgd, va);
pte = pte_offset(pmd, va);
update.ptr = pte;
update.ptr = virt_to_machine(pte);
pteval = *(unsigned long *)pte;
update.val = pteval & ~_PAGE_PRESENT;
HYPERVISOR_mmu_update(&update, 1);
@@ -95,7 +95,9 @@ void MULTICALL_flush_page_update_queue(void)
#if MMU_UPDATE_DEBUG > 0
DEBUG_allow_pt_reads();
#endif
queue_multicall2(__HYPERVISOR_mmu_update, (unsigned long)update_queue, idx);
queue_multicall2(__HYPERVISOR_mmu_update,
(unsigned long)update_queue,
idx);
idx = 0;
}
spin_unlock_irqrestore(&update_lock, flags);
@@ -134,7 +136,7 @@ void queue_l1_entry_update(pte_t *ptr, unsigned long val)
#if MMU_UPDATE_DEBUG > 0
DEBUG_disallow_pt_read((unsigned long)ptr);
#endif
update_queue[idx].ptr = (unsigned long)ptr;
update_queue[idx].ptr = virt_to_machine(ptr);
update_queue[idx].val = val;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
@@ -144,7 +146,7 @@ void queue_l2_entry_update(pmd_t *ptr, unsigned long val)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = (unsigned long)ptr;
update_queue[idx].ptr = virt_to_machine(ptr);
update_queue[idx].val = val;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
+5 -9
View File
@@ -113,13 +113,10 @@ static inline void set_pte_phys (unsigned long vaddr,
}
pte = pte_offset(pmd, vaddr);
#if 0 /* Not in Xen, since this breaks clear_fixmap. */
if (pte_val(*pte))
pte_ERROR(*pte);
#endif
/* We queue directly, avoiding hidden phys->machine translation. */
queue_l1_entry_update(pte, phys | pgprot_val(prot));
if ( pte_io(*pte) || (pgprot_val(prot) & _PAGE_IO) )
queue_unchecked_mmu_update(pte, phys | pgprot_val(prot));
else
queue_l1_entry_update(pte, phys | pgprot_val(prot));
/*
* It's enough to flush this one mapping.
@@ -137,8 +134,7 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys,
printk("Invalid __set_fixmap\n");
return;
}
set_pte_phys(address, phys,
__pgprot(pgprot_val(PAGE_KERNEL)|pgprot_val(flags)));
set_pte_phys(address, phys, flags);
}
void clear_fixmap(enum fixed_addresses idx)
@@ -202,14 +202,15 @@ void __init *bt_ioremap(unsigned long machine_addr, unsigned long size)
*/
nrpages = size >> PAGE_SHIFT;
if (nrpages > NR_FIX_BTMAPS)
return NULL;
return NULL;
/*
* Ok, go for it..
*/
idx = FIX_BTMAP_BEGIN;
while (nrpages > 0) {
set_fixmap(idx, machine_addr);
__set_fixmap(idx, machine_addr,
__pgprot(__PAGE_KERNEL|_PAGE_IO));
machine_addr += PAGE_SIZE;
--idx;
--nrpages;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.