bitkeeper revision 1.1236.12.11 (422de58bI6Rru29oYT0ipOgZZhpqZw)

resolve of grant tables merge
This commit is contained in:
cwc22@centipede.cl.cam.ac.uk committed 2005-03-08 17:48:59 +00:00
commit 3f9c9eae7a
12 files changed
+891 -103

No files matched your search

+1
View File
@@ -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;
+1
View File
@@ -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
+57
View File
@@ -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__ */
+143
View File
@@ -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
View File
@@ -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
View File
@@ -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(&gt->lock);
ASSERT(d->grant_table->active != NULL);
ASSERT(d->grant_table->shared != NULL);
for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
{
act = &gt->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 = &gt->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(&gt->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 = &gt->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");
}
/*
+16 -1
View File
@@ -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__ */
+56
View File
@@ -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)
{
+28 -3
View File
@@ -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__ */
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.