mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
bitkeeper revision 1.1236.12.11 (422de58bI6Rru29oYT0ipOgZZhpqZw)
resolve of grant tables merge
This commit is contained in:
commit
3f9c9eae7a
12 files changed
+891
-103
No files matched your search
@@ -558,6 +558,7 @@
|
||||
3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxc/xc_domain.c
|
||||
40278d99BLsfUv3qxv0I8C1sClZ0ow tools/libxc/xc_elf.h
|
||||
403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/libxc/xc_evtchn.c
|
||||
4227c129ZKjJPNYooHVzBCyinf7Y6Q tools/libxc/xc_gnttab.c
|
||||
40e03333Eegw8czSWvHsbKxrRZJjRA tools/libxc/xc_io.c
|
||||
40e03333vrWGbLAhyJjXlqCHaJt7eA tools/libxc/xc_io.h
|
||||
3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxc/xc_linux_build.c
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* 2. Accessing others' memory reservations via grant references.
|
||||
* (i.e., mechanisms for both sender and recipient of grant references)
|
||||
*
|
||||
* Copyright (c) 2005, Christopher Clark
|
||||
* Copyright (c) 2004, K A Fraser
|
||||
*/
|
||||
|
||||
@@ -14,6 +15,9 @@
|
||||
#include <linux/sched.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm-xen/xen_proc.h>
|
||||
#include <asm-xen/linux-public/privcmd.h>
|
||||
#include <asm-xen/gnttab.h>
|
||||
|
||||
#ifndef set_fixmap_ma
|
||||
@@ -28,8 +32,13 @@
|
||||
#define ASSERT(_p) ((void)0)
|
||||
#endif
|
||||
|
||||
#define WPRINTK(fmt, args...) \
|
||||
printk(KERN_WARNING "xen_grant: " fmt, ##args)
|
||||
|
||||
|
||||
EXPORT_SYMBOL(gnttab_grant_foreign_access);
|
||||
EXPORT_SYMBOL(gnttab_end_foreign_access);
|
||||
EXPORT_SYMBOL(gnttab_query_foreign_access);
|
||||
EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
|
||||
EXPORT_SYMBOL(gnttab_end_foreign_transfer);
|
||||
|
||||
@@ -39,6 +48,10 @@ static grant_ref_t gnttab_free_head;
|
||||
|
||||
static grant_entry_t *shared;
|
||||
|
||||
/* /proc/xen/grant */
|
||||
static struct proc_dir_entry *grant_pde;
|
||||
|
||||
|
||||
/*
|
||||
* Lock-free grant-entry allocator
|
||||
*/
|
||||
@@ -84,9 +97,18 @@ gnttab_grant_foreign_access(
|
||||
return ref;
|
||||
}
|
||||
|
||||
int
|
||||
gnttab_query_foreign_access( grant_ref_t ref )
|
||||
{
|
||||
u16 nflags;
|
||||
|
||||
nflags = shared[ref].flags;
|
||||
|
||||
return ( nflags & (GTF_reading|GTF_writing) );
|
||||
}
|
||||
|
||||
void
|
||||
gnttab_end_foreign_access(
|
||||
grant_ref_t ref, int readonly)
|
||||
gnttab_end_foreign_access( grant_ref_t ref, int readonly )
|
||||
{
|
||||
u16 flags, nflags;
|
||||
|
||||
@@ -141,7 +163,72 @@ gnttab_end_foreign_transfer(
|
||||
return frame;
|
||||
}
|
||||
|
||||
void __init gnttab_init(void)
|
||||
static int grant_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long data)
|
||||
{
|
||||
int ret;
|
||||
privcmd_hypercall_t hypercall;
|
||||
|
||||
if ( cmd != IOCTL_PRIVCMD_HYPERCALL )
|
||||
return -ENOSYS;
|
||||
|
||||
if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
|
||||
return -EFAULT;
|
||||
|
||||
if ( hypercall.op != __HYPERVISOR_grant_table_op )
|
||||
return -ENOSYS;
|
||||
|
||||
/* hypercall-invoking asm taken from privcmd.c */
|
||||
__asm__ __volatile__ (
|
||||
"pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
|
||||
"movl 4(%%eax),%%ebx ;"
|
||||
"movl 8(%%eax),%%ecx ;"
|
||||
"movl 12(%%eax),%%edx ;"
|
||||
"movl 16(%%eax),%%esi ;"
|
||||
"movl 20(%%eax),%%edi ;"
|
||||
"movl (%%eax),%%eax ;"
|
||||
TRAP_INSTR "; "
|
||||
"popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
|
||||
: "=a" (ret) : "0" (&hypercall) : "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct file_operations grant_file_ops = {
|
||||
ioctl: grant_ioctl,
|
||||
};
|
||||
|
||||
static int grant_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len;
|
||||
unsigned int i;
|
||||
grant_entry_t *gt;
|
||||
|
||||
gt = (grant_entry_t *)shared;
|
||||
len = 0;
|
||||
|
||||
for ( i = 0; i < NR_GRANT_REFS; i++ )
|
||||
if ( gt[i].flags )
|
||||
len += sprintf( page + len,
|
||||
"Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n",
|
||||
i,
|
||||
gt[i].flags,
|
||||
gt[i].domid,
|
||||
gt[i].frame );
|
||||
|
||||
*eof = 1;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int grant_write(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
/* TODO: implement this */
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int __init gnttab_init(void)
|
||||
{
|
||||
gnttab_setup_table_t setup;
|
||||
unsigned long frame;
|
||||
@@ -160,4 +247,25 @@ void __init gnttab_init(void)
|
||||
|
||||
set_fixmap_ma(FIX_GNTTAB, frame << PAGE_SHIFT);
|
||||
shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB);
|
||||
|
||||
/*
|
||||
* /proc/xen/grant : used by libxc to access grant tables
|
||||
*/
|
||||
if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL )
|
||||
{
|
||||
WPRINTK("Unable to create grant xen proc entry\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
grant_file_ops.read = grant_pde->proc_fops->read;
|
||||
grant_file_ops.write = grant_pde->proc_fops->write;
|
||||
|
||||
grant_pde->proc_fops = &grant_file_ops;
|
||||
|
||||
grant_pde->read_proc = &grant_read;
|
||||
grant_pde->write_proc = &grant_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(gnttab_init);
|
||||
@@ -32,4 +32,8 @@ unsigned long
|
||||
gnttab_end_foreign_transfer(
|
||||
grant_ref_t ref);
|
||||
|
||||
int
|
||||
gnttab_query_foreign_access(
|
||||
grant_ref_t ref );
|
||||
|
||||
#endif /* __ASM_GNTTAB_H__ */
|
||||
@@ -536,7 +536,7 @@ HYPERVISOR_grant_table_op(
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3)
|
||||
: "0" (__HYPERVISOR_grant_table_op), "1" (cmd), "2" (count), "3" (uop)
|
||||
: "0" (__HYPERVISOR_grant_table_op), "1" (cmd), "2" (uop), "3" (count)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -20,6 +20,7 @@ SRCS += xc_atropos.c
|
||||
SRCS += xc_bvtsched.c
|
||||
SRCS += xc_domain.c
|
||||
SRCS += xc_evtchn.c
|
||||
SRCS += xc_gnttab.c
|
||||
SRCS += xc_io.c
|
||||
SRCS += xc_linux_build.c
|
||||
SRCS += xc_plan9_build.c
|
||||
|
||||
@@ -411,4 +411,61 @@ void *xc_map_foreign_batch(int xc_handle, u32 dom, int prot,
|
||||
int xc_get_pfn_list(int xc_handle, u32 domid, unsigned long *pfn_buf,
|
||||
unsigned long max_pfns);
|
||||
|
||||
/*\
|
||||
* GRANT TABLE FUNCTIONS
|
||||
\*/
|
||||
|
||||
/**
|
||||
* This function opens a handle to the more restricted grant table hypervisor
|
||||
* interface. This may be used where the standard interface is not
|
||||
* available because the domain is not privileged.
|
||||
* This function can be called multiple times within a single process.
|
||||
* Multiple processes can have an open hypervisor interface at the same time.
|
||||
*
|
||||
* Each call to this function should have a corresponding call to
|
||||
* xc_grant_interface_close().
|
||||
*
|
||||
* This function can fail if a Xen-enabled kernel is not currently running.
|
||||
*
|
||||
* @return a handle to the hypervisor grant table interface or -1 on failure
|
||||
*/
|
||||
int xc_grant_interface_open(void);
|
||||
|
||||
/**
|
||||
* This function closes an open grant table hypervisor interface.
|
||||
*
|
||||
* This function can fail if the handle does not represent an open interface or
|
||||
* if there were problems closing the interface.
|
||||
*
|
||||
* @parm xc_handle a handle to an open grant table hypervisor interface
|
||||
* @return 0 on success, -1 otherwise.
|
||||
*/
|
||||
int xc_grant_interface_close(int xc_handle);
|
||||
|
||||
int xc_gnttab_map_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
u32 dom,
|
||||
u16 ref,
|
||||
u16 flags,
|
||||
s16 *handle,
|
||||
memory_t *dev_bus_addr);
|
||||
|
||||
int xc_gnttab_unmap_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
memory_t dev_bus_addr,
|
||||
u16 handle,
|
||||
s16 *status);
|
||||
|
||||
int xc_gnttab_setup_table(int xc_handle,
|
||||
u32 dom,
|
||||
u16 nr_frames,
|
||||
s16 *status,
|
||||
memory_t **frame_list);
|
||||
|
||||
/* Grant debug builds only: */
|
||||
int xc_gnttab_dump_table(int xc_handle,
|
||||
u32 dom,
|
||||
s16 *status);
|
||||
|
||||
|
||||
#endif /* __XC_H__ */
|
||||
@@ -0,0 +1,143 @@
|
||||
/******************************************************************************
|
||||
* xc_gnttab.c
|
||||
*
|
||||
* API for manipulating and accessing grant tables
|
||||
*
|
||||
* Copyright (c) 2005 Christopher Clark
|
||||
* based on xc_evtchn.c Copyright (c) 2004, K A Fraser.
|
||||
*/
|
||||
|
||||
#include "xc_private.h"
|
||||
#include "xen/grant_table.h"
|
||||
|
||||
static int
|
||||
do_gnttab_op( int xc_handle,
|
||||
unsigned long cmd,
|
||||
gnttab_op_t *op,
|
||||
unsigned long count )
|
||||
{
|
||||
int ret = -1;
|
||||
privcmd_hypercall_t hypercall;
|
||||
|
||||
hypercall.op = __HYPERVISOR_grant_table_op;
|
||||
hypercall.arg[0] = cmd;
|
||||
hypercall.arg[1] = (unsigned long)(op);
|
||||
hypercall.arg[2] = count;
|
||||
|
||||
if ( mlock(op, sizeof(*op)) != 0 )
|
||||
{
|
||||
PERROR("Could not lock memory for Xen hypercall");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
|
||||
{
|
||||
printf("do_gnttab_op: hypercall returned error %d\n", ret);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
out2: (void)munlock(op, sizeof(*op));
|
||||
out1: return ret;
|
||||
}
|
||||
|
||||
|
||||
int xc_gnttab_map_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
u32 dom,
|
||||
u16 ref,
|
||||
u16 flags,
|
||||
s16 *handle,
|
||||
memory_t *dev_bus_addr)
|
||||
{
|
||||
gnttab_op_t op;
|
||||
int rc;
|
||||
|
||||
op.u.map_grant_ref.host_virt_addr = host_virt_addr;
|
||||
op.u.map_grant_ref.dom = (domid_t)dom;
|
||||
op.u.map_grant_ref.ref = ref;
|
||||
op.u.map_grant_ref.flags = flags;
|
||||
|
||||
if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_map_grant_ref, &op, 1)) == 0 )
|
||||
{
|
||||
*handle = op.u.map_grant_ref.handle;
|
||||
*dev_bus_addr = op.u.map_grant_ref.dev_bus_addr;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int xc_gnttab_unmap_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
memory_t dev_bus_addr,
|
||||
u16 handle,
|
||||
s16 *status)
|
||||
{
|
||||
gnttab_op_t op;
|
||||
int rc;
|
||||
|
||||
op.u.unmap_grant_ref.host_virt_addr = host_virt_addr;
|
||||
op.u.unmap_grant_ref.dev_bus_addr = dev_bus_addr;
|
||||
op.u.unmap_grant_ref.handle = handle;
|
||||
|
||||
if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_unmap_grant_ref, &op, 1)) == 0 )
|
||||
*status = op.u.unmap_grant_ref.status;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int xc_gnttab_setup_table(int xc_handle,
|
||||
u32 dom,
|
||||
u16 nr_frames,
|
||||
s16 *status,
|
||||
memory_t **frame_list)
|
||||
{
|
||||
gnttab_op_t op;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
op.u.setup_table.dom = (domid_t)dom;
|
||||
op.u.setup_table.nr_frames = nr_frames;
|
||||
|
||||
if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_setup_table, &op, 1)) == 0 )
|
||||
{
|
||||
*status = op.u.setup_table.status;
|
||||
for ( i = 0; i < nr_frames; i++ )
|
||||
{
|
||||
(*frame_list)[i] = op.u.setup_table.frame_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int xc_gnttab_dump_table(int xc_handle,
|
||||
u32 dom,
|
||||
s16 *status)
|
||||
{
|
||||
gnttab_op_t op;
|
||||
int rc;
|
||||
|
||||
op.u.dump_table.dom = (domid_t)dom;
|
||||
|
||||
printf("xc_gnttab_dump_table: domain %d\n", dom);
|
||||
|
||||
if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_dump_table, &op, 1)) == 0 )
|
||||
*status = op.u.dump_table.status;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int xc_grant_interface_open(void)
|
||||
{
|
||||
int fd = open("/proc/xen/grant", O_RDWR);
|
||||
if ( fd == -1 )
|
||||
PERROR("Could not obtain handle on grant command interface");
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
int xc_grant_interface_close(int xc_grant_handle)
|
||||
{
|
||||
return close(xc_grant_handle);
|
||||
}
|
||||
+120
-50
@@ -1060,14 +1060,14 @@ void free_page_type(struct pfn_info *page, unsigned int type)
|
||||
}
|
||||
|
||||
|
||||
void put_page_type(struct pfn_info *page)
|
||||
void put_page_types(struct pfn_info *page, u32 decrement)
|
||||
{
|
||||
u32 nx, x, y = page->u.inuse.type_info;
|
||||
|
||||
again:
|
||||
do {
|
||||
x = y;
|
||||
nx = x - 1;
|
||||
nx = x - decrement;
|
||||
|
||||
ASSERT((x & PGT_count_mask) != 0);
|
||||
|
||||
@@ -1911,16 +1911,124 @@ int do_mmu_update(
|
||||
return rc;
|
||||
}
|
||||
|
||||
void update_shadow_va_mapping(unsigned long va,
|
||||
unsigned long val,
|
||||
struct exec_domain *ed,
|
||||
struct domain *d)
|
||||
{
|
||||
/* This function assumes the caller is holding the domain's BIGLOCK
|
||||
* and is running in a shadow mode
|
||||
*/
|
||||
|
||||
unsigned long sval = 0;
|
||||
|
||||
l1pte_propagate_from_guest(d, &val, &sval);
|
||||
|
||||
if ( unlikely(__put_user(sval, ((unsigned long *)(
|
||||
&shadow_linear_pg_table[l1_linear_offset(va)])))) )
|
||||
{
|
||||
/*
|
||||
* Since L2's are guranteed RW, failure indicates either that the
|
||||
* page was not shadowed, or that the L2 entry has not yet been
|
||||
* updated to reflect the shadow.
|
||||
*/
|
||||
l2_pgentry_t gpde = linear_l2_table[l2_table_offset(va)];
|
||||
unsigned long gpfn = l2_pgentry_val(gpde) >> PAGE_SHIFT;
|
||||
|
||||
if (get_shadow_status(d, gpfn))
|
||||
{
|
||||
unsigned long gmfn = __gpfn_to_mfn(d, gpfn);
|
||||
unsigned long *gl1e = map_domain_mem(gmfn << PAGE_SHIFT);
|
||||
unsigned l1_idx = l1_table_offset(va);
|
||||
gl1e[l1_idx] = sval;
|
||||
unmap_domain_mem(gl1e);
|
||||
put_shadow_status(d);
|
||||
|
||||
perfc_incrc(shadow_update_va_fail1);
|
||||
}
|
||||
else
|
||||
perfc_incrc(shadow_update_va_fail2);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're in log-dirty mode then we need to note that we've updated
|
||||
* the PTE in the PT-holding page. We need the machine frame number
|
||||
* for this.
|
||||
*/
|
||||
if ( shadow_mode_log_dirty(d) )
|
||||
mark_dirty(d, va_to_l1mfn(va));
|
||||
|
||||
check_pagetable(d, ed->arch.guest_table, "va"); /* debug */
|
||||
}
|
||||
|
||||
int update_grant_va_mapping(unsigned long va,
|
||||
unsigned long _nl1e,
|
||||
struct domain *d,
|
||||
struct exec_domain *ed)
|
||||
{
|
||||
/* Caller must:
|
||||
* . own d's BIGLOCK
|
||||
* . already have 'get_page' correctly on the to-be-installed nl1e
|
||||
* . be responsible for flushing the TLB
|
||||
* . check PTE being installed isn't DISALLOWED
|
||||
*/
|
||||
|
||||
/* Return value:
|
||||
* -ve : error
|
||||
* 0 : done
|
||||
* GNTUPDVA_prev_ro : done & prior mapping was ro to same frame
|
||||
* GNTUPDVA_prev_rw : done & prior mapping was rw to same frame
|
||||
*/
|
||||
|
||||
int rc = 0;
|
||||
l1_pgentry_t *pl1e;
|
||||
unsigned long _ol1e;
|
||||
|
||||
cleanup_writable_pagetable(d);
|
||||
|
||||
pl1e = &linear_pg_table[l1_linear_offset(va)];
|
||||
|
||||
if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) )
|
||||
rc = -EINVAL;
|
||||
else
|
||||
{
|
||||
l1_pgentry_t ol1e = mk_l1_pgentry(_ol1e);
|
||||
|
||||
if ( update_l1e(pl1e, ol1e, mk_l1_pgentry(_nl1e)) )
|
||||
{
|
||||
/* overwrote different mfn? */
|
||||
if (((_ol1e ^ _nl1e) & (PADDR_MASK & PAGE_MASK)) != 0)
|
||||
{
|
||||
rc = 0;
|
||||
put_page_from_l1e(ol1e, d);
|
||||
}
|
||||
else
|
||||
rc = ((_ol1e & _PAGE_RW) ? GNTUPDVA_prev_rw
|
||||
: GNTUPDVA_prev_ro );
|
||||
/* use return code to avoid nasty grant table
|
||||
* slow path in put_page_from_l1e -- caller
|
||||
* must handle ref count instead. */
|
||||
}
|
||||
else
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
if ( unlikely(shadow_mode_enabled(d)) )
|
||||
update_shadow_va_mapping(va, _nl1e, ed, d);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int do_update_va_mapping(unsigned long va,
|
||||
unsigned long val,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct exec_domain *ed = current;
|
||||
struct domain *d = ed->domain;
|
||||
int err = 0;
|
||||
unsigned int cpu = ed->processor;
|
||||
unsigned long deferred_ops;
|
||||
struct exec_domain *ed = current;
|
||||
struct domain *d = ed->domain;
|
||||
unsigned int cpu = ed->processor;
|
||||
unsigned long deferred_ops;
|
||||
int rc = 0;
|
||||
|
||||
perfc_incrc(calls_to_update_va);
|
||||
|
||||
@@ -1941,52 +2049,14 @@ int do_update_va_mapping(unsigned long va,
|
||||
|
||||
if ( unlikely(!mod_l1_entry(&linear_pg_table[l1_linear_offset(va)],
|
||||
mk_l1_pgentry(val))) )
|
||||
err = -EINVAL;
|
||||
rc = -EINVAL;
|
||||
|
||||
if ( unlikely(shadow_mode_enabled(d)) )
|
||||
{
|
||||
unsigned long sval = 0;
|
||||
if ( shadow_mode_external(current->domain) )
|
||||
BUG(); // can't use linear_l2_table with external tables.
|
||||
|
||||
l1pte_propagate_from_guest(d, &val, &sval);
|
||||
|
||||
if ( unlikely(__put_user(sval, ((unsigned long *)(
|
||||
&shadow_linear_pg_table[l1_linear_offset(va)])))) )
|
||||
{
|
||||
/*
|
||||
* Since L2's are guranteed RW, failure indicates either that the
|
||||
* page was not shadowed, or that the L2 entry has not yet been
|
||||
* updated to reflect the shadow.
|
||||
*/
|
||||
if ( shadow_mode_external(current->domain) )
|
||||
BUG(); // can't use linear_l2_table with external tables.
|
||||
|
||||
l2_pgentry_t gpde = linear_l2_table[l2_table_offset(va)];
|
||||
unsigned long gpfn = l2_pgentry_val(gpde) >> PAGE_SHIFT;
|
||||
|
||||
if (get_shadow_status(d, gpfn))
|
||||
{
|
||||
unsigned long gmfn = __gpfn_to_mfn(d, gpfn);
|
||||
unsigned long *gl1e = map_domain_mem(gmfn << PAGE_SHIFT);
|
||||
unsigned l1_idx = l1_table_offset(va);
|
||||
gl1e[l1_idx] = sval;
|
||||
unmap_domain_mem(gl1e);
|
||||
put_shadow_status(d);
|
||||
|
||||
perfc_incrc(shadow_update_va_fail1);
|
||||
}
|
||||
else
|
||||
perfc_incrc(shadow_update_va_fail2);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're in log-dirty mode then we need to note that we've updated
|
||||
* the PTE in the PT-holding page. We need the machine frame number
|
||||
* for this.
|
||||
*/
|
||||
if ( shadow_mode_log_dirty(d) )
|
||||
mark_dirty(d, va_to_l1mfn(va));
|
||||
|
||||
check_pagetable(d, ed->arch.guest_table, "va"); /* debug */
|
||||
update_shadow_va_mapping(va, val, ed, d);
|
||||
}
|
||||
|
||||
deferred_ops = percpu_info[cpu].deferred_ops;
|
||||
@@ -2003,7 +2073,7 @@ int do_update_va_mapping(unsigned long va,
|
||||
|
||||
UNLOCK_BIGLOCK(d);
|
||||
|
||||
return err;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int do_update_va_mapping_otherdomain(unsigned long va,
|
||||
|
||||
+353
-45
@@ -4,6 +4,7 @@
|
||||
* Mechanism for granting foreign access to page frames, and receiving
|
||||
* page-ownership transfers.
|
||||
*
|
||||
* Copyright (c) 2005 Christopher Clark
|
||||
* Copyright (c) 2004 K A Fraser
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,8 +22,12 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define GRANT_DEBUG 1
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/sched.h>
|
||||
#include <asm-x86/mm.h>
|
||||
#include <asm-x86/shadow.h>
|
||||
|
||||
#define PIN_FAIL(_rc, _f, _a...) \
|
||||
do { \
|
||||
@@ -50,19 +55,24 @@ put_maptrack_handle(
|
||||
t->maptrack_head = handle;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
__gnttab_map_grant_ref(
|
||||
gnttab_map_grant_ref_t *uop)
|
||||
gnttab_map_grant_ref_t *uop,
|
||||
unsigned long *va)
|
||||
{
|
||||
domid_t dom, sdom;
|
||||
grant_ref_t ref;
|
||||
struct domain *ld, *rd;
|
||||
u16 flags, sflags;
|
||||
int handle;
|
||||
domid_t dom, sdom;
|
||||
grant_ref_t ref;
|
||||
struct domain *ld, *rd;
|
||||
struct exec_domain *led;
|
||||
u16 flags, sflags;
|
||||
int handle;
|
||||
active_grant_entry_t *act;
|
||||
grant_entry_t *sha;
|
||||
s16 rc = 0;
|
||||
unsigned long frame;
|
||||
grant_entry_t *sha;
|
||||
s16 rc = 0;
|
||||
unsigned long frame = 0, host_virt_addr;
|
||||
|
||||
/* Returns 0 if TLB flush / invalidate required by caller.
|
||||
* va will indicate the address to be invalidated. */
|
||||
|
||||
/*
|
||||
* We bound the number of times we retry CMPXCHG on memory locations that
|
||||
@@ -74,23 +84,33 @@ __gnttab_map_grant_ref(
|
||||
*/
|
||||
int retries = 0;
|
||||
|
||||
ld = current->domain;
|
||||
led = current;
|
||||
ld = led->domain;
|
||||
|
||||
/* Bitwise-OR avoids short-circuiting which screws control flow. */
|
||||
if ( unlikely(__get_user(dom, &uop->dom) |
|
||||
__get_user(ref, &uop->ref) |
|
||||
__get_user(host_virt_addr, &uop->host_virt_addr) |
|
||||
__get_user(flags, &uop->flags)) )
|
||||
{
|
||||
DPRINTK("Fault while reading gnttab_map_grant_ref_t.\n");
|
||||
return; /* don't set status */
|
||||
return -EFAULT; /* don't set status */
|
||||
}
|
||||
|
||||
if ( unlikely(ref >= NR_GRANT_ENTRIES) ||
|
||||
if ( ((host_virt_addr != 0) || (flags & GNTMAP_host_map) ) &&
|
||||
unlikely(!__addr_ok(host_virt_addr)))
|
||||
{
|
||||
DPRINTK("Bad virtual address (%x) or flags (%x).\n", host_virt_addr, flags);
|
||||
(void)__put_user(GNTST_bad_virt_addr, &uop->handle);
|
||||
return GNTST_bad_gntref;
|
||||
}
|
||||
|
||||
if ( unlikely(ref >= NR_GRANT_ENTRIES) ||
|
||||
unlikely((flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
|
||||
{
|
||||
DPRINTK("Bad ref (%d) or flags (%x).\n", ref, flags);
|
||||
(void)__put_user(GNTST_bad_gntref, &uop->handle);
|
||||
return;
|
||||
return GNTST_bad_gntref;
|
||||
}
|
||||
|
||||
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
|
||||
@@ -100,7 +120,7 @@ __gnttab_map_grant_ref(
|
||||
put_domain(rd);
|
||||
DPRINTK("Could not find domain %d\n", dom);
|
||||
(void)__put_user(GNTST_bad_domain, &uop->handle);
|
||||
return;
|
||||
return GNTST_bad_domain;
|
||||
}
|
||||
|
||||
if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) )
|
||||
@@ -108,14 +128,16 @@ __gnttab_map_grant_ref(
|
||||
put_domain(rd);
|
||||
DPRINTK("No more map handles available\n");
|
||||
(void)__put_user(GNTST_no_device_space, &uop->handle);
|
||||
return;
|
||||
return GNTST_no_device_space;
|
||||
}
|
||||
DPRINTK("Mapping grant ref (%hu) for domain (%hu) with flags (%x)\n",
|
||||
ref, dom, flags);
|
||||
|
||||
act = &rd->grant_table->active[ref];
|
||||
sha = &rd->grant_table->shared[ref];
|
||||
|
||||
spin_lock(&rd->grant_table->lock);
|
||||
|
||||
|
||||
if ( act->pin == 0 )
|
||||
{
|
||||
/* CASE 1: Activating a previously inactive entry. */
|
||||
@@ -148,7 +170,7 @@ __gnttab_map_grant_ref(
|
||||
|
||||
/* NB. prev_scombo is updated in place to seen value. */
|
||||
if ( unlikely(cmpxchg_user((u32 *)&sha->flags,
|
||||
prev_scombo,
|
||||
prev_scombo,
|
||||
new_scombo)) )
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Fault while modifying shared flags and domid.\n");
|
||||
@@ -168,16 +190,18 @@ __gnttab_map_grant_ref(
|
||||
}
|
||||
|
||||
/* rmb(); */ /* not on x86 */
|
||||
frame = sha->frame;
|
||||
if ( unlikely(!pfn_is_ram(frame)) ||
|
||||
unlikely(!((flags & GNTMAP_readonly) ?
|
||||
get_page(&frame_table[frame], rd) :
|
||||
get_page_and_type(&frame_table[frame], rd,
|
||||
|
||||
frame = __translate_gpfn_to_mfn(rd, sha->frame);
|
||||
|
||||
if ( unlikely(!pfn_is_ram(frame)) ||
|
||||
unlikely(!((flags & GNTMAP_readonly) ?
|
||||
get_page(&frame_table[frame], rd) :
|
||||
get_page_and_type(&frame_table[frame], rd,
|
||||
PGT_writable_page))) )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Could not pin the granted frame!\n");
|
||||
}
|
||||
|
||||
@@ -230,7 +254,9 @@ __gnttab_map_grant_ref(
|
||||
sflags = prev_sflags;
|
||||
}
|
||||
|
||||
if ( unlikely(!get_page_type(&frame_table[act->frame],
|
||||
frame = act->frame;
|
||||
|
||||
if ( unlikely(!get_page_type(&frame_table[frame],
|
||||
PGT_writable_page)) )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
@@ -251,34 +277,91 @@ __gnttab_map_grant_ref(
|
||||
ld->grant_table->maptrack[handle].ref_and_flags =
|
||||
(ref << MAPTRACK_REF_SHIFT) | (flags & MAPTRACK_GNTMAP_MASK);
|
||||
|
||||
if ( (host_virt_addr != 0) && (flags & GNTMAP_host_map) )
|
||||
{
|
||||
/* Write update into the pagetable
|
||||
*/
|
||||
if ( 0 > (rc = update_grant_va_mapping( host_virt_addr,
|
||||
(frame << PAGE_SHIFT) | _PAGE_PRESENT |
|
||||
_PAGE_ACCESSED |
|
||||
_PAGE_DIRTY |
|
||||
((flags & GNTMAP_readonly) ? 0 : _PAGE_RW),
|
||||
ld, led )) )
|
||||
{
|
||||
/* Abort. */
|
||||
act->pin -= (flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
|
||||
if ( flags & GNTMAP_readonly )
|
||||
act->pin -= GNTPIN_hstr_inc;
|
||||
else
|
||||
{
|
||||
act->pin -= GNTPIN_hstw_inc;
|
||||
if ( (act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) == 0 )
|
||||
put_page_type(&frame_table[frame]);
|
||||
|
||||
if ( act->pin == 0 )
|
||||
put_page(&frame_table[frame]);
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( rc == GNTUPDVA_prev_ro )
|
||||
act->pin -= GNTPIN_hstr_inc;
|
||||
|
||||
if ( rc == GNTUPDVA_prev_rw )
|
||||
{
|
||||
act->pin -= GNTPIN_hstw_inc;
|
||||
put_page_type(&frame_table[frame]);
|
||||
}
|
||||
rc = 0;
|
||||
*va = host_virt_addr;
|
||||
|
||||
/* IMPORTANT: must flush / invalidate entry in TLB.
|
||||
* This is done in the outer gnttab_map_grant_ref when return 0.
|
||||
*/
|
||||
}
|
||||
|
||||
if ( flags & GNTMAP_device_map )
|
||||
(void)__put_user(frame, &uop->dev_bus_addr);
|
||||
|
||||
/* Unchecked and unconditional. */
|
||||
(void)__put_user(handle, &uop->handle);
|
||||
(void)__put_user(act->frame, &uop->dev_bus_addr);
|
||||
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
put_domain(rd);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
(void)__put_user(rc, &uop->handle);
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
put_domain(rd);
|
||||
put_maptrack_handle(ld->grant_table, handle);
|
||||
put_maptrack_handle(ld->grant_table, handle); //cwc22: check this
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long
|
||||
gnttab_map_grant_ref(
|
||||
gnttab_map_grant_ref_t *uop, unsigned int count)
|
||||
{
|
||||
int i;
|
||||
int i, flush = 0;
|
||||
unsigned long va;
|
||||
|
||||
for ( i = 0; i < count; i++ )
|
||||
__gnttab_map_grant_ref(&uop[i]);
|
||||
if ( __gnttab_map_grant_ref(&uop[i], &va) == 0)
|
||||
flush++;
|
||||
|
||||
if ( flush == 1 )
|
||||
__flush_tlb_one(va);
|
||||
else if ( flush )
|
||||
local_flush_tlb();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
__gnttab_unmap_grant_ref(
|
||||
gnttab_unmap_grant_ref_t *uop)
|
||||
gnttab_unmap_grant_ref_t *uop,
|
||||
unsigned long *va)
|
||||
{
|
||||
domid_t dom;
|
||||
grant_ref_t ref;
|
||||
@@ -288,7 +371,7 @@ __gnttab_unmap_grant_ref(
|
||||
active_grant_entry_t *act;
|
||||
grant_entry_t *sha;
|
||||
grant_mapping_t *map;
|
||||
s16 rc = 0;
|
||||
s16 rc = -EFAULT;
|
||||
unsigned long frame, virt;
|
||||
|
||||
ld = current->domain;
|
||||
@@ -299,7 +382,7 @@ __gnttab_unmap_grant_ref(
|
||||
__get_user(handle, &uop->handle)) )
|
||||
{
|
||||
DPRINTK("Fault while reading gnttab_unmap_grant_ref_t.\n");
|
||||
return; /* don't set status */
|
||||
return -EFAULT; /* don't set status */
|
||||
}
|
||||
|
||||
map = &ld->grant_table->maptrack[handle];
|
||||
@@ -309,7 +392,7 @@ __gnttab_unmap_grant_ref(
|
||||
{
|
||||
DPRINTK("Bad handle (%d).\n", handle);
|
||||
(void)__put_user(GNTST_bad_handle, &uop->status);
|
||||
return;
|
||||
return GNTST_bad_handle;
|
||||
}
|
||||
|
||||
dom = map->domid;
|
||||
@@ -322,8 +405,10 @@ __gnttab_unmap_grant_ref(
|
||||
put_domain(rd);
|
||||
DPRINTK("Could not find domain %d\n", dom);
|
||||
(void)__put_user(GNTST_bad_domain, &uop->status);
|
||||
return;
|
||||
return GNTST_bad_domain;
|
||||
}
|
||||
DPRINTK("Unmapping grant ref (%hu) for domain (%hu) with handle (%hu)\n",
|
||||
ref, dom, handle);
|
||||
|
||||
act = &rd->grant_table->active[ref];
|
||||
sha = &rd->grant_table->shared[ref];
|
||||
@@ -344,12 +429,53 @@ __gnttab_unmap_grant_ref(
|
||||
frame = act->frame;
|
||||
}
|
||||
|
||||
if ( (virt != 0) && (map->ref_and_flags & GNTMAP_host_map) )
|
||||
if ( (virt != 0) &&
|
||||
(map->ref_and_flags & GNTMAP_host_map) &&
|
||||
((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0))
|
||||
{
|
||||
act->pin -= (map->ref_and_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
l1_pgentry_t *pl1e;
|
||||
unsigned long _ol1e;
|
||||
|
||||
pl1e = &linear_pg_table[l1_linear_offset(virt)];
|
||||
|
||||
if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) )
|
||||
{
|
||||
DPRINTK("Could not find PTE entry for address %x\n", virt);
|
||||
rc = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check that the virtual address supplied is actually
|
||||
* mapped to act->frame.
|
||||
*/
|
||||
if ( unlikely((_ol1e >> PAGE_SHIFT) != frame ))
|
||||
{
|
||||
DPRINTK("PTE entry %x for address %x doesn't match frame %x\n",
|
||||
_ol1e, virt, frame);
|
||||
rc = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* This code _requires_ that the act->pin bits are updated
|
||||
* if a mapping is ever switched between RO and RW.
|
||||
*/
|
||||
act->pin -= ( _ol1e & _PAGE_RW ) ? GNTPIN_hstw_inc
|
||||
: GNTPIN_hstr_inc;
|
||||
|
||||
/* Delete pagetable entry
|
||||
*/
|
||||
if ( unlikely(__put_user(0, (unsigned long *)pl1e)))
|
||||
{
|
||||
DPRINTK("Cannot delete PTE entry at %x for virtual address %x\n",
|
||||
pl1e, virt);
|
||||
rc = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
rc = 0;
|
||||
*va = virt;
|
||||
}
|
||||
|
||||
/* If the last writable mapping has been removed, put_page_type */
|
||||
if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
|
||||
!(map->ref_and_flags & GNTMAP_readonly) )
|
||||
{
|
||||
@@ -367,15 +493,24 @@ __gnttab_unmap_grant_ref(
|
||||
(void)__put_user(rc, &uop->status);
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
put_domain(rd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long
|
||||
gnttab_unmap_grant_ref(
|
||||
gnttab_unmap_grant_ref_t *uop, unsigned int count)
|
||||
{
|
||||
int i;
|
||||
int i, flush = 0;
|
||||
unsigned long va = 0;
|
||||
|
||||
for ( i = 0; i < count; i++ )
|
||||
__gnttab_unmap_grant_ref(&uop[i]);
|
||||
if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0)
|
||||
flush++;
|
||||
|
||||
if ( flush == 1 )
|
||||
__flush_tlb_one(va);
|
||||
else if ( flush )
|
||||
local_flush_tlb();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -423,7 +558,7 @@ gnttab_setup_table(
|
||||
{
|
||||
ASSERT(d->grant_table != NULL);
|
||||
(void)put_user(GNTST_okay, &uop->status);
|
||||
(void)put_user(virt_to_phys(d->grant_table) >> PAGE_SHIFT,
|
||||
(void)put_user(virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT,
|
||||
&uop->frame_list[0]);
|
||||
}
|
||||
|
||||
@@ -431,14 +566,99 @@ gnttab_setup_table(
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef GRANT_DEBUG
|
||||
static int
|
||||
gnttab_dump_table(gnttab_dump_table_t *uop)
|
||||
{
|
||||
grant_table_t *gt;
|
||||
gnttab_dump_table_t op;
|
||||
struct domain *d;
|
||||
u32 shared_mfn;
|
||||
active_grant_entry_t *act;
|
||||
grant_entry_t sha_copy;
|
||||
grant_mapping_t *maptrack;
|
||||
int i;
|
||||
|
||||
|
||||
if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) )
|
||||
{
|
||||
DPRINTK("Fault while reading gnttab_dump_table_t.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if ( op.dom == DOMID_SELF )
|
||||
{
|
||||
op.dom = current->domain->id;
|
||||
}
|
||||
|
||||
if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) )
|
||||
{
|
||||
DPRINTK("Bad domid %d.\n", op.dom);
|
||||
(void)put_user(GNTST_bad_domain, &uop->status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASSERT(d->grant_table != NULL);
|
||||
gt = d->grant_table;
|
||||
(void)put_user(GNTST_okay, &uop->status);
|
||||
|
||||
shared_mfn = virt_to_phys(d->grant_table->shared);
|
||||
|
||||
DPRINTK("Grant table for dom (%hu) MFN (%x)\n",
|
||||
op.dom, shared_mfn);
|
||||
|
||||
spin_lock(>->lock);
|
||||
|
||||
ASSERT(d->grant_table->active != NULL);
|
||||
ASSERT(d->grant_table->shared != NULL);
|
||||
|
||||
for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
|
||||
{
|
||||
act = >->active[i];
|
||||
sha_copy = gt->shared[i];
|
||||
|
||||
if ( act->pin || act->domid || act->frame ||
|
||||
sha_copy.flags || sha_copy.domid || sha_copy.frame )
|
||||
{
|
||||
DPRINTK("Grant: dom (%hu) ACTIVE (%d) pin:(%x) dom:(%hu) frame:(%u)\n",
|
||||
op.dom, i, act->pin, act->domid, act->frame);
|
||||
DPRINTK("Grant: dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%u)\n",
|
||||
op.dom, i, sha_copy.flags, sha_copy.domid, sha_copy.frame);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ASSERT(d->grant_table->maptrack != NULL);
|
||||
|
||||
for ( i = 0; i < NR_MAPTRACK_ENTRIES; i++ )
|
||||
{
|
||||
maptrack = >->maptrack[i];
|
||||
|
||||
if ( maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK )
|
||||
{
|
||||
DPRINTK("Grant: dom (%hu) MAP (%d) ref:(%hu) flags:(%x) dom:(%hu)\n",
|
||||
op.dom, i,
|
||||
maptrack->ref_and_flags >> MAPTRACK_REF_SHIFT,
|
||||
maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK,
|
||||
maptrack->domid);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(>->lock);
|
||||
|
||||
put_domain(d);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
long
|
||||
do_grant_table_op(
|
||||
unsigned int cmd, void *uop, unsigned int count)
|
||||
{
|
||||
long rc;
|
||||
|
||||
/* XXX stubbed out XXX */
|
||||
return -ENOSYS;
|
||||
DPRINTK("Grant: table operation (%u) count: (%u)\n", cmd, count);
|
||||
|
||||
if ( count > 512 )
|
||||
return -EINVAL;
|
||||
@@ -462,6 +682,11 @@ do_grant_table_op(
|
||||
case GNTTABOP_setup_table:
|
||||
rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count);
|
||||
break;
|
||||
#ifdef GRANT_DEBUG
|
||||
case GNTTABOP_dump_table:
|
||||
rc = gnttab_dump_table((gnttab_dump_table_t *)uop);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
break;
|
||||
@@ -476,6 +701,11 @@ int
|
||||
gnttab_check_unmap(
|
||||
struct domain *rd, struct domain *ld, unsigned long frame, int readonly)
|
||||
{
|
||||
/* TODO: beat the caller around the head with a brick.
|
||||
* have to walk the grant tables to find this thing.
|
||||
*/
|
||||
/*DPRINTK("gnttab_check_unmap remote dom(%d) local dom(%d) frame (%x) flags(%x).\n",
|
||||
rd->id, ld->id, frame, readonly);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -552,8 +782,17 @@ gnttab_prepare_for_transfer(
|
||||
|
||||
void
|
||||
gnttab_notify_transfer(
|
||||
struct domain *rd, grant_ref_t ref, unsigned long frame)
|
||||
struct domain *rd, grant_ref_t ref, unsigned long sframe)
|
||||
{
|
||||
unsigned long frame;
|
||||
|
||||
/* cwc22
|
||||
* TODO: this requires that the machine_to_phys_mapping
|
||||
* has already been updated, so the accept_transfer hypercall
|
||||
* must do this.
|
||||
*/
|
||||
frame = __mfn_to_gpfn(rd, sframe);
|
||||
|
||||
wmb(); /* Ensure that the reassignment is globally visible. */
|
||||
rd->grant_table->shared[ref].frame = frame;
|
||||
}
|
||||
@@ -607,6 +846,71 @@ grant_table_create(
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void
|
||||
gnttab_release_all_mappings(grant_table_t *gt)
|
||||
{
|
||||
grant_mapping_t *map;
|
||||
domid_t dom;
|
||||
grant_ref_t ref;
|
||||
u16 handle;
|
||||
u32 pincount;
|
||||
struct domain *ld, *rd;
|
||||
unsigned long frame;
|
||||
active_grant_entry_t *act;
|
||||
grant_entry_t *sha;
|
||||
|
||||
ld = current->domain;
|
||||
|
||||
for ( handle = 0; handle < NR_MAPTRACK_ENTRIES; handle++ )
|
||||
{
|
||||
map = >->maptrack[handle];
|
||||
|
||||
if ( map->ref_and_flags & MAPTRACK_GNTMAP_MASK )
|
||||
{
|
||||
dom = map->domid;
|
||||
ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT;
|
||||
|
||||
DPRINTK("Grant release (%hu) ref:(%hu) flags:(%x) dom:(%hu)\n",
|
||||
handle, ref,
|
||||
map->ref_and_flags & MAPTRACK_GNTMAP_MASK, dom);
|
||||
|
||||
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
|
||||
unlikely(ld == rd) )
|
||||
{
|
||||
if ( rd != NULL )
|
||||
put_domain(rd);
|
||||
|
||||
printk(KERN_WARNING "Grant release: Could not find domain %d\n", dom);
|
||||
continue;
|
||||
}
|
||||
|
||||
act = &rd->grant_table->active[ref];
|
||||
sha = &rd->grant_table->shared[ref];
|
||||
|
||||
spin_lock(&rd->grant_table->lock);
|
||||
|
||||
frame = act->frame;
|
||||
|
||||
pincount = ((act->pin & GNTPIN_hstw_mask) >> GNTPIN_hstw_shift) +
|
||||
((act->pin & GNTPIN_devw_mask) >> GNTPIN_devw_shift);
|
||||
|
||||
if ( pincount > 0 )
|
||||
put_page_types(&frame_table[frame], pincount);
|
||||
|
||||
put_page(&frame_table[frame]);
|
||||
|
||||
act->pin = 0;
|
||||
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
|
||||
put_domain(rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grant_table_destroy(
|
||||
struct domain *d)
|
||||
@@ -615,6 +919,9 @@ grant_table_destroy(
|
||||
|
||||
if ( (t = d->grant_table) != NULL )
|
||||
{
|
||||
if ( t->maptrack != NULL )
|
||||
gnttab_release_all_mappings(t);
|
||||
|
||||
/* Free memory relating to this grant table. */
|
||||
d->grant_table = NULL;
|
||||
free_xenheap_page((unsigned long)t->shared);
|
||||
@@ -629,6 +936,7 @@ grant_table_init(
|
||||
void)
|
||||
{
|
||||
/* Nothing. */
|
||||
DPRINTK("Grant table init\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -182,9 +182,14 @@ static inline int get_page(struct pfn_info *page,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void put_page_type(struct pfn_info *page);
|
||||
void put_page_types(struct pfn_info *page, u32 decrement);
|
||||
int get_page_type(struct pfn_info *page, u32 type);
|
||||
|
||||
static inline void put_page_type(struct pfn_info *page)
|
||||
{
|
||||
put_page_types(page, 1);
|
||||
}
|
||||
|
||||
static inline void put_page_and_type(struct pfn_info *page)
|
||||
{
|
||||
put_page_type(page);
|
||||
@@ -336,4 +341,14 @@ void audit_domains(void);
|
||||
|
||||
void propagate_page_fault(unsigned long addr, u16 error_code);
|
||||
|
||||
/* update_grant_va_mapping
|
||||
* Caller must own d's BIGLOCK, is responsible for flushing the TLB,
|
||||
* and have already get_page'd */
|
||||
int update_grant_va_mapping(unsigned long va,
|
||||
unsigned long val,
|
||||
struct domain *d,
|
||||
struct exec_domain *ed);
|
||||
#define GNTUPDVA_prev_ro 1
|
||||
#define GNTUPDVA_prev_rw 2
|
||||
|
||||
#endif /* __ASM_X86_MM_H__ */
|
||||
@@ -61,6 +61,62 @@ extern void vmx_shadow_clear_state(struct domain *);
|
||||
? phys_to_machine_mapping(gpfn) \
|
||||
: (gpfn) )
|
||||
|
||||
#define __translate_gpfn_to_mfn(_d, gpfn) \
|
||||
( (shadow_mode_translate(_d)) \
|
||||
? translate_gpfn_to_mfn(_d, gpfn) \
|
||||
: (gpfn) )
|
||||
|
||||
static inline unsigned long
|
||||
translate_gpfn_to_mfn(struct domain *rd, unsigned long gpfn)
|
||||
{
|
||||
unsigned long ma_of_phys_to_mach;
|
||||
l2_pgentry_t *l2_table;
|
||||
l2_pgentry_t l2_entry;
|
||||
unsigned long ma_of_l1_table;
|
||||
l1_pgentry_t *l1_table;
|
||||
l1_pgentry_t pte;
|
||||
unsigned long mfn = 0;
|
||||
|
||||
/*
|
||||
* translation of: (domain, gpfn) -> mfn
|
||||
* where domain != current, and is in translate shadow mode
|
||||
*/
|
||||
|
||||
ASSERT( shadow_mode_translate(rd) );
|
||||
|
||||
shadow_lock(rd);
|
||||
|
||||
/* TODO: check using shadow_lock is correct
|
||||
* TODO: move arch.phys_table from exec_domain to domain
|
||||
* - use of zero index is a hack - FIXME
|
||||
*/
|
||||
|
||||
ma_of_phys_to_mach = pagetable_val( (rd->exec_domain[0])->arch.phys_table );
|
||||
|
||||
l2_table = (l2_pgentry_t *) map_domain_mem( ma_of_phys_to_mach );
|
||||
l2_entry = l2_table[ gpfn >> (L2_PAGETABLE_SHIFT - PAGE_SHIFT) ];
|
||||
|
||||
unmap_domain_mem( l2_table );
|
||||
|
||||
if ( l2_pgentry_val(l2_entry) == 0 )
|
||||
goto unlock_out;
|
||||
|
||||
ma_of_l1_table = l2_pgentry_to_phys( l2_entry );
|
||||
|
||||
l1_table = (l1_pgentry_t *) map_domain_mem( ma_of_l1_table );
|
||||
pte = l1_table[ (gpfn >> (L1_PAGETABLE_SHIFT - PAGE_SHIFT)) &
|
||||
(L1_PAGETABLE_ENTRIES - 1 ) ];
|
||||
|
||||
unmap_domain_mem( l1_table );
|
||||
|
||||
mfn = l1_pgentry_to_pfn(pte);
|
||||
|
||||
unlock_out:
|
||||
shadow_unlock(rd);
|
||||
|
||||
return mfn;
|
||||
}
|
||||
|
||||
extern void __shadow_mode_disable(struct domain *d);
|
||||
static inline void shadow_mode_disable(struct domain *d)
|
||||
{
|
||||
|
||||
@@ -206,6 +206,19 @@ typedef struct {
|
||||
MEMORY_PADDING;
|
||||
} PACKED gnttab_setup_table_t; /* 16 bytes */
|
||||
|
||||
/*
|
||||
* GNTTABOP_dump_table: Dump the contents of the grant table to the
|
||||
* xen console. Debugging use only.
|
||||
*/
|
||||
#define GNTTABOP_dump_table 3
|
||||
typedef struct {
|
||||
/* IN parameters. */
|
||||
domid_t dom; /* 0 */
|
||||
/* OUT parameters. */
|
||||
s16 status; /* 2: GNTST_* */
|
||||
} PACKED gnttab_dump_table_t; /* 4 bytes */
|
||||
|
||||
|
||||
/*
|
||||
* Bitfield values for update_pin_status.flags.
|
||||
*/
|
||||
@@ -233,9 +246,10 @@ typedef struct {
|
||||
#define GNTST_general_error (-1) /* General undefined error. */
|
||||
#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */
|
||||
#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */
|
||||
#define GNTST_bad_handle (-3) /* Unrecognised or inappropriate handle. */
|
||||
#define GNTST_no_device_space (-4) /* Out of space in I/O MMU. */
|
||||
#define GNTST_permission_denied (-5) /* Not enough privilege for operation. */
|
||||
#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */
|
||||
#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */
|
||||
#define GNTST_no_device_space (-6) /* Out of space in I/O MMU. */
|
||||
#define GNTST_permission_denied (-7) /* Not enough privilege for operation. */
|
||||
|
||||
#define GNTTABOP_error_msgs { \
|
||||
"okay", \
|
||||
@@ -243,9 +257,20 @@ typedef struct {
|
||||
"unrecognised domain id", \
|
||||
"invalid grant reference", \
|
||||
"invalid mapping handle", \
|
||||
"invalid virtual address", \
|
||||
"no spare translation slot in the I/O MMU", \
|
||||
"permission denied" \
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
union { /* 0 */
|
||||
gnttab_map_grant_ref_t map_grant_ref;
|
||||
gnttab_unmap_grant_ref_t unmap_grant_ref;
|
||||
gnttab_setup_table_t setup_table;
|
||||
gnttab_dump_table_t dump_table;
|
||||
u8 __dummy[24];
|
||||
} PACKED u;
|
||||
} PACKED gnttab_op_t; /* 32 bytes */
|
||||
|
||||
#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
|
||||