mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
bitkeeper revision 1.1159.1.216 (41656f2ek7HkbBXpAt8AAbtJEyjlTg)
Grant-table interface redone.
This commit is contained in:
1 parent
37d9a01369
commit
6213b696ba
11 files changed
+535
-505
No files matched your search
@@ -33,22 +33,9 @@ EXPORT_SYMBOL(gnttab_end_foreign_access);
|
||||
EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
|
||||
EXPORT_SYMBOL(gnttab_end_foreign_transfer);
|
||||
|
||||
struct gntent_auxinfo {
|
||||
u16 write_pin, read_pin; /* reference counts */
|
||||
u16 inuse;
|
||||
grant_ref_t next; /* hash chain */
|
||||
};
|
||||
|
||||
#define NR_GRANT_REFS 512
|
||||
|
||||
static struct gntent_auxinfo auxtab[NR_GRANT_REFS];
|
||||
static grant_ref_t gnttab_free_list[NR_GRANT_REFS];
|
||||
static grant_ref_t gnttab_free_head;
|
||||
static spinlock_t gnttab_lock;
|
||||
|
||||
#define HASH_INVALID (0xFFFFU)
|
||||
#define GNTTAB_HASH_SZ 512
|
||||
#define GNTTAB_HASH(_f) ((_f) & (GNTTAB_HASH_SZ-1))
|
||||
static grant_ref_t gnttab_hash[GNTTAB_HASH_SZ];
|
||||
|
||||
static grant_entry_t *shared;
|
||||
|
||||
@@ -56,14 +43,14 @@ static grant_entry_t *shared;
|
||||
* Lock-free grant-entry allocator
|
||||
*/
|
||||
|
||||
static inline grant_ref_t
|
||||
static inline int
|
||||
get_free_entry(
|
||||
void)
|
||||
{
|
||||
grant_ref_t fh, nfh = gnttab_free_head;
|
||||
do { fh = nfh; }
|
||||
do { if ( unlikely((fh = nfh) == NR_GRANT_REFS) ) return -1; }
|
||||
while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh,
|
||||
auxtab[fh].next)) != fh) );
|
||||
gnttab_free_list[fh])) != fh) );
|
||||
return fh;
|
||||
}
|
||||
|
||||
@@ -72,109 +59,55 @@ put_free_entry(
|
||||
grant_ref_t ref)
|
||||
{
|
||||
grant_ref_t fh, nfh = gnttab_free_head;
|
||||
do { auxtab[ref].next = fh = nfh; wmb(); }
|
||||
do { gnttab_free_list[ref] = fh = nfh; wmb(); }
|
||||
while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh, ref)) != fh) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Public interface functions
|
||||
* Public grant-issuing interface functions
|
||||
*/
|
||||
|
||||
grant_ref_t
|
||||
int
|
||||
gnttab_grant_foreign_access(
|
||||
domid_t domid, unsigned long frame, int readonly)
|
||||
{
|
||||
unsigned long flags;
|
||||
grant_ref_t ref;
|
||||
|
||||
spin_lock_irqsave(&gnttab_lock, flags);
|
||||
|
||||
for ( ref = gnttab_hash[GNTTAB_HASH(frame)];
|
||||
ref != HASH_INVALID;
|
||||
ref = auxtab[ref].next )
|
||||
{
|
||||
if ( auxtab[ref].inuse && (shared[ref].frame == frame) )
|
||||
{
|
||||
if ( readonly )
|
||||
auxtab[ref].read_pin++;
|
||||
else if ( auxtab[ref].write_pin++ == 0 )
|
||||
clear_bit(_GTF_readonly, (unsigned long *)&shared[ref].flags);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ref = get_free_entry();
|
||||
auxtab[ref].inuse = 1;
|
||||
auxtab[ref].read_pin = !!readonly;
|
||||
auxtab[ref].write_pin = !readonly;
|
||||
auxtab[ref].next = gnttab_hash[GNTTAB_HASH(frame)];
|
||||
gnttab_hash[GNTTAB_HASH(frame)] = ref;
|
||||
int ref;
|
||||
|
||||
if ( unlikely((ref = get_free_entry()) == -1) )
|
||||
return -ENOSPC;
|
||||
|
||||
shared[ref].frame = frame;
|
||||
shared[ref].domid = domid;
|
||||
wmb();
|
||||
shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore(&gnttab_lock, flags);
|
||||
return 0;
|
||||
return ref;
|
||||
}
|
||||
|
||||
void
|
||||
gnttab_end_foreign_access(
|
||||
grant_ref_t ref, int readonly)
|
||||
{
|
||||
unsigned long flags, frame = shared[ref].frame;
|
||||
grant_ref_t *pref;
|
||||
u16 sflags, nsflags;
|
||||
u16 flags, nflags;
|
||||
|
||||
spin_lock_irqsave(&gnttab_lock, flags);
|
||||
|
||||
if ( readonly )
|
||||
{
|
||||
if ( (auxtab[ref].read_pin-- == 0) && (auxtab[ref].write_pin == 0) )
|
||||
goto delete;
|
||||
}
|
||||
else if ( auxtab[ref].write_pin-- == 0 )
|
||||
{
|
||||
if ( auxtab[ref].read_pin == 0 )
|
||||
goto delete;
|
||||
nsflags = shared[ref].flags;
|
||||
do {
|
||||
if ( (sflags = nsflags) & GTF_writing )
|
||||
printk(KERN_ALERT "WARNING: g.e. still in use for writing!\n");
|
||||
}
|
||||
while ( (nsflags = cmpxchg(&shared[ref].flags, sflags,
|
||||
sflags | GTF_readonly)) != sflags );
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
delete:
|
||||
nsflags = shared[ref].flags;
|
||||
nflags = shared[ref].flags;
|
||||
do {
|
||||
if ( (sflags = nsflags) & (GTF_reading|GTF_writing) )
|
||||
if ( (flags = nflags) & (GTF_reading|GTF_writing) )
|
||||
printk(KERN_ALERT "WARNING: g.e. still in use!\n");
|
||||
}
|
||||
while ( (nsflags = cmpxchg(&shared[ref].flags, sflags, 0)) != sflags );
|
||||
while ( (nflags = cmpxchg(&shared[ref].flags, flags, 0)) != flags );
|
||||
|
||||
pref = &gnttab_hash[GNTTAB_HASH(frame)];
|
||||
while ( *pref != ref )
|
||||
pref = &auxtab[*pref].next;
|
||||
*pref = auxtab[ref].next;
|
||||
|
||||
auxtab[ref].inuse = 0;
|
||||
put_free_entry(ref);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&gnttab_lock, flags);
|
||||
}
|
||||
|
||||
grant_ref_t
|
||||
int
|
||||
gnttab_grant_foreign_transfer(
|
||||
domid_t domid)
|
||||
{
|
||||
grant_ref_t ref = get_free_entry();
|
||||
int ref;
|
||||
|
||||
if ( unlikely((ref = get_free_entry()) == -1) )
|
||||
return -ENOSPC;
|
||||
|
||||
shared[ref].frame = 0;
|
||||
shared[ref].domid = domid;
|
||||
@@ -210,23 +143,19 @@ gnttab_end_foreign_transfer(
|
||||
|
||||
void __init gnttab_init(void)
|
||||
{
|
||||
int i;
|
||||
gnttab_op_t gntop;
|
||||
unsigned long frame;
|
||||
gnttab_setup_table_t setup;
|
||||
unsigned long frame;
|
||||
int i;
|
||||
|
||||
spin_lock_init(&gnttab_lock);
|
||||
for ( i = 0; i < NR_GRANT_REFS; i++ )
|
||||
gnttab_free_list[i] = i + 1;
|
||||
|
||||
for ( i = 0; i < GNTTAB_HASH_SZ; i++ )
|
||||
{
|
||||
gnttab_hash[i] = HASH_INVALID;
|
||||
auxtab[i].next = i+1;
|
||||
}
|
||||
|
||||
gntop.cmd = GNTTABOP_setup_table;
|
||||
gntop.u.setup_table.dom = DOMID_SELF;
|
||||
gntop.u.setup_table.nr_frames = 1;
|
||||
gntop.u.setup_table.frame_list = &frame;
|
||||
if ( HYPERVISOR_grant_table_op(&gntop) != 0 )
|
||||
setup.dom = DOMID_SELF;
|
||||
setup.nr_frames = 1;
|
||||
setup.frame_list = &frame;
|
||||
if ( HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0 )
|
||||
BUG();
|
||||
if ( setup.status != 0 )
|
||||
BUG();
|
||||
|
||||
set_fixmap_ma(FIX_GNTTAB, frame << PAGE_SHIFT);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <asm-xen/hypervisor.h>
|
||||
#include <asm-xen/hypervisor-ifs/grant_table.h>
|
||||
|
||||
grant_ref_t
|
||||
int
|
||||
gnttab_grant_foreign_access(
|
||||
domid_t domid, unsigned long frame, int readonly);
|
||||
|
||||
@@ -24,7 +24,7 @@ void
|
||||
gnttab_end_foreign_access(
|
||||
grant_ref_t ref, int readonly);
|
||||
|
||||
grant_ref_t
|
||||
int
|
||||
gnttab_grant_foreign_transfer(
|
||||
domid_t domid);
|
||||
|
||||
|
||||
@@ -181,7 +181,9 @@ void deallocate_lowmem_region(unsigned long vstart, unsigned long pages);
|
||||
* Assembler stubs for hyper-calls.
|
||||
*/
|
||||
|
||||
static inline int HYPERVISOR_set_trap_table(trap_info_t *table)
|
||||
static inline int
|
||||
HYPERVISOR_set_trap_table(
|
||||
trap_info_t *table)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -192,8 +194,9 @@ static inline int HYPERVISOR_set_trap_table(trap_info_t *table)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_mmu_update(mmu_update_t *req, int count,
|
||||
int *success_count)
|
||||
static inline int
|
||||
HYPERVISOR_mmu_update(
|
||||
mmu_update_t *req, int count, int *success_count)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -204,7 +207,9 @@ static inline int HYPERVISOR_mmu_update(mmu_update_t *req, int count,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
|
||||
static inline int
|
||||
HYPERVISOR_set_gdt(
|
||||
unsigned long *frame_list, int entries)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -216,7 +221,9 @@ static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
|
||||
static inline int
|
||||
HYPERVISOR_stack_switch(
|
||||
unsigned long ss, unsigned long esp)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -227,7 +234,8 @@ static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_set_callbacks(
|
||||
static inline int
|
||||
HYPERVISOR_set_callbacks(
|
||||
unsigned long event_selector, unsigned long event_address,
|
||||
unsigned long failsafe_selector, unsigned long failsafe_address)
|
||||
{
|
||||
@@ -241,7 +249,9 @@ static inline int HYPERVISOR_set_callbacks(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_fpu_taskswitch(void)
|
||||
static inline int
|
||||
HYPERVISOR_fpu_taskswitch(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -251,7 +261,9 @@ static inline int HYPERVISOR_fpu_taskswitch(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_yield(void)
|
||||
static inline int
|
||||
HYPERVISOR_yield(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -262,7 +274,9 @@ static inline int HYPERVISOR_yield(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_block(void)
|
||||
static inline int
|
||||
HYPERVISOR_block(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -273,7 +287,9 @@ static inline int HYPERVISOR_block(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_shutdown(void)
|
||||
static inline int
|
||||
HYPERVISOR_shutdown(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -285,7 +301,9 @@ static inline int HYPERVISOR_shutdown(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_reboot(void)
|
||||
static inline int
|
||||
HYPERVISOR_reboot(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -297,7 +315,9 @@ static inline int HYPERVISOR_reboot(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_suspend(unsigned long srec)
|
||||
static inline int
|
||||
HYPERVISOR_suspend(
|
||||
unsigned long srec)
|
||||
{
|
||||
int ret;
|
||||
/* NB. On suspend, control software expects a suspend record in %esi. */
|
||||
@@ -310,7 +330,9 @@ static inline int HYPERVISOR_suspend(unsigned long srec)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long HYPERVISOR_set_timer_op(u64 timeout)
|
||||
static inline long
|
||||
HYPERVISOR_set_timer_op(
|
||||
u64 timeout)
|
||||
{
|
||||
int ret;
|
||||
unsigned long timeout_hi = (unsigned long)(timeout>>32);
|
||||
@@ -323,7 +345,9 @@ static inline long HYPERVISOR_set_timer_op(u64 timeout)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_dom0_op(dom0_op_t *dom0_op)
|
||||
static inline int
|
||||
HYPERVISOR_dom0_op(
|
||||
dom0_op_t *dom0_op)
|
||||
{
|
||||
int ret;
|
||||
dom0_op->interface_version = DOM0_INTERFACE_VERSION;
|
||||
@@ -335,7 +359,9 @@ static inline int HYPERVISOR_dom0_op(dom0_op_t *dom0_op)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value)
|
||||
static inline int
|
||||
HYPERVISOR_set_debugreg(
|
||||
int reg, unsigned long value)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -346,7 +372,9 @@ static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline unsigned long HYPERVISOR_get_debugreg(int reg)
|
||||
static inline unsigned long
|
||||
HYPERVISOR_get_debugreg(
|
||||
int reg)
|
||||
{
|
||||
unsigned long ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -357,7 +385,8 @@ static inline unsigned long HYPERVISOR_get_debugreg(int reg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_update_descriptor(
|
||||
static inline int
|
||||
HYPERVISOR_update_descriptor(
|
||||
unsigned long ma, unsigned long word1, unsigned long word2)
|
||||
{
|
||||
int ret;
|
||||
@@ -369,7 +398,9 @@ static inline int HYPERVISOR_update_descriptor(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_set_fast_trap(int idx)
|
||||
static inline int
|
||||
HYPERVISOR_set_fast_trap(
|
||||
int idx)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -380,10 +411,10 @@ static inline int HYPERVISOR_set_fast_trap(int idx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_dom_mem_op(unsigned int op,
|
||||
unsigned long *extent_list,
|
||||
unsigned long nr_extents,
|
||||
unsigned int extent_order)
|
||||
static inline int
|
||||
HYPERVISOR_dom_mem_op(
|
||||
unsigned int op, unsigned long *extent_list,
|
||||
unsigned long nr_extents, unsigned int extent_order)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -396,7 +427,9 @@ static inline int HYPERVISOR_dom_mem_op(unsigned int op,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_multicall(void *call_list, int nr_calls)
|
||||
static inline int
|
||||
HYPERVISOR_multicall(
|
||||
void *call_list, int nr_calls)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -407,7 +440,8 @@ static inline int HYPERVISOR_multicall(void *call_list, int nr_calls)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_update_va_mapping(
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping(
|
||||
unsigned long page_nr, pte_t new_val, unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
@@ -426,7 +460,9 @@ static inline int HYPERVISOR_update_va_mapping(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_event_channel_op(void *op)
|
||||
static inline int
|
||||
HYPERVISOR_event_channel_op(
|
||||
void *op)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -437,7 +473,9 @@ static inline int HYPERVISOR_event_channel_op(void *op)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_xen_version(int cmd)
|
||||
static inline int
|
||||
HYPERVISOR_xen_version(
|
||||
int cmd)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -448,7 +486,9 @@ static inline int HYPERVISOR_xen_version(int cmd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_console_io(int cmd, int count, char *str)
|
||||
static inline int
|
||||
HYPERVISOR_console_io(
|
||||
int cmd, int count, char *str)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -459,7 +499,9 @@ static inline int HYPERVISOR_console_io(int cmd, int count, char *str)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_physdev_op(void *physdev_op)
|
||||
static inline int
|
||||
HYPERVISOR_physdev_op(
|
||||
void *physdev_op)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
@@ -470,18 +512,21 @@ static inline int HYPERVISOR_physdev_op(void *physdev_op)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_grant_table_op(void *gnttab_op)
|
||||
static inline int
|
||||
HYPERVISOR_grant_table_op(
|
||||
unsigned int cmd, void *uop, unsigned int count)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_grant_table_op),
|
||||
"b" (gnttab_op) : "memory" );
|
||||
"b" (cmd), "c" (count), "d" (uop) : "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_update_va_mapping_otherdomain(
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping_otherdomain(
|
||||
unsigned long page_nr, pte_t new_val, unsigned long flags, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
@@ -494,7 +539,9 @@ static inline int HYPERVISOR_update_va_mapping_otherdomain(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type)
|
||||
static inline int
|
||||
HYPERVISOR_vm_assist(
|
||||
unsigned int cmd, unsigned int type)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
|
||||
@@ -708,7 +708,7 @@ int construct_dom0(struct domain *p,
|
||||
page = &frame_table[mfn];
|
||||
page->u.inuse.domain = p;
|
||||
page->u.inuse.type_info = 0;
|
||||
page->count_info = PGC_always_set | PGC_allocated | 1;
|
||||
page->count_info = PGC_allocated | 1;
|
||||
list_add_tail(&page->list, &p->page_list);
|
||||
p->tot_pages++; p->max_pages++;
|
||||
}
|
||||
|
||||
+5
-37
@@ -164,9 +164,6 @@ void arch_init_memory(void)
|
||||
|
||||
memset(percpu_info, 0, sizeof(percpu_info));
|
||||
|
||||
for ( mfn = 0; mfn < max_page; mfn++ )
|
||||
frame_table[mfn].count_info |= PGC_always_set;
|
||||
|
||||
/* Initialise to a magic of 0x55555555 so easier to spot bugs later. */
|
||||
memset(machine_to_phys_mapping, 0x55, 4<<20);
|
||||
|
||||
@@ -193,9 +190,9 @@ void arch_init_memory(void)
|
||||
mfn < virt_to_phys(&machine_to_phys_mapping[1<<20])>>PAGE_SHIFT;
|
||||
mfn++ )
|
||||
{
|
||||
frame_table[mfn].count_info |= PGC_allocated | 1;
|
||||
frame_table[mfn].u.inuse.type_info = PGT_gdt_page | 1; /* non-RW */
|
||||
frame_table[mfn].u.inuse.domain = dom_xen;
|
||||
frame_table[mfn].count_info = PGC_allocated | 1;
|
||||
frame_table[mfn].u.inuse.type_info = PGT_gdt_page | 1; /* non-RW */
|
||||
frame_table[mfn].u.inuse.domain = dom_xen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,8 +400,6 @@ get_page_from_l1e(
|
||||
|
||||
if ( unlikely(!pfn_is_ram(pfn)) )
|
||||
{
|
||||
/* SPECIAL CASE 1. Mapping an I/O page. */
|
||||
|
||||
/* Revert to caller privileges if FD == DOMID_IO. */
|
||||
if ( d == dom_io )
|
||||
d = current;
|
||||
@@ -420,33 +415,7 @@ get_page_from_l1e(
|
||||
}
|
||||
|
||||
if ( unlikely(!get_page_from_pagenr(pfn, d)) )
|
||||
{
|
||||
/* SPECIAL CASE 2. Mapping a foreign page via a grant table. */
|
||||
|
||||
int rc;
|
||||
struct domain *e;
|
||||
u32 count_info;
|
||||
/*
|
||||
* Yuk! Amazingly this is the simplest way to get a guaranteed atomic
|
||||
* snapshot of a 64-bit value on IA32. x86/64 solves this of course!
|
||||
* Basically it's a no-op CMPXCHG, to get us the current contents.
|
||||
* No need for LOCK prefix -- we know that count_info is never zero
|
||||
* because it contains PGC_always_set.
|
||||
*/
|
||||
ASSERT(test_bit(_PGC_always_set, &page->count_info));
|
||||
__asm__ __volatile__(
|
||||
"cmpxchg8b %2"
|
||||
: "=d" (e), "=a" (count_info),
|
||||
"=m" (*(volatile u64 *)(&page->count_info))
|
||||
: "0" (0), "1" (0), "c" (0), "b" (0) );
|
||||
if ( unlikely((count_info & PGC_count_mask) == 0) ||
|
||||
unlikely(e == NULL) || unlikely(!get_domain(e)) )
|
||||
return 0;
|
||||
rc = gnttab_try_map(
|
||||
e, d, pfn, (l1v & _PAGE_RW) ? GNTTAB_MAP_RW : GNTTAB_MAP_RO);
|
||||
put_domain(e);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if ( l1v & _PAGE_RW )
|
||||
{
|
||||
@@ -510,8 +479,7 @@ static void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
|
||||
* mappings and which unmappings are counted via the grant entry, but
|
||||
* really it doesn't matter as privileged domains have carte blanche.
|
||||
*/
|
||||
if ( likely(gnttab_try_map(e, d, pfn, (l1v & _PAGE_RW) ?
|
||||
GNTTAB_UNMAP_RW : GNTTAB_UNMAP_RO)) )
|
||||
if ( likely(gnttab_check_unmap(e, d, pfn, !(l1v & _PAGE_RW))) )
|
||||
return;
|
||||
/* Assume this mapping was made via MMUEXT_SET_FOREIGNDOM... */
|
||||
}
|
||||
|
||||
+260
-225
@@ -27,65 +27,50 @@
|
||||
#define PIN_FAIL(_rc, _f, _a...) \
|
||||
do { \
|
||||
DPRINTK( _f, ## _a ); \
|
||||
rc = -(_rc); \
|
||||
goto out; \
|
||||
rc = (_rc); \
|
||||
goto fail; \
|
||||
} while ( 0 )
|
||||
|
||||
static inline int
|
||||
get_maptrack_handle(
|
||||
grant_table_t *t)
|
||||
{
|
||||
unsigned int h;
|
||||
if ( unlikely((h = t->maptrack_head) == NR_MAPTRACK_ENTRIES) )
|
||||
return -1;
|
||||
t->maptrack_head = t->maptrack[h].ref_and_flags >> MAPTRACK_REF_SHIFT;
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_tlb_flush(
|
||||
active_grant_entry_t *a)
|
||||
put_maptrack_handle(
|
||||
grant_table_t *t, int handle)
|
||||
{
|
||||
if ( unlikely(NEED_FLUSH(tlbflush_time[smp_processor_id()],
|
||||
a->tlbflush_timestamp)) )
|
||||
{
|
||||
perfc_incr(need_flush_tlb_flush);
|
||||
local_flush_tlb();
|
||||
}
|
||||
t->maptrack[handle].ref_and_flags = t->maptrack_head << MAPTRACK_REF_SHIFT;
|
||||
t->maptrack_head = handle;
|
||||
}
|
||||
|
||||
static void
|
||||
make_entry_mappable(
|
||||
grant_table_t *t, active_grant_entry_t *a)
|
||||
{
|
||||
u16 *ph = &t->maphash[GNT_MAPHASH(a->frame)];
|
||||
a->next = *ph;
|
||||
*ph = a - t->active;
|
||||
}
|
||||
|
||||
static void
|
||||
make_entry_unmappable(
|
||||
grant_table_t *t, active_grant_entry_t *a)
|
||||
{
|
||||
active_grant_entry_t *p;
|
||||
u16 *ph = &t->maphash[GNT_MAPHASH(a->frame)];
|
||||
while ( (p = &t->active[*ph]) != a )
|
||||
ph = &p->next;
|
||||
*ph = a->next;
|
||||
a->next = GNT_MAPHASH_INVALID;
|
||||
check_tlb_flush(a);
|
||||
}
|
||||
|
||||
static long
|
||||
gnttab_update_pin_status(
|
||||
gnttab_update_pin_status_t *uop)
|
||||
__gnttab_map_grant_ref(
|
||||
gnttab_map_grant_ref_t *uop)
|
||||
{
|
||||
domid_t dom, sdom;
|
||||
grant_ref_t ref;
|
||||
u16 pin_flags;
|
||||
struct domain *ld, *rd;
|
||||
u16 sflags;
|
||||
u16 flags, sflags;
|
||||
int handle;
|
||||
active_grant_entry_t *act;
|
||||
grant_entry_t *sha;
|
||||
long rc = 0;
|
||||
s16 rc = 0;
|
||||
unsigned long frame;
|
||||
|
||||
/*
|
||||
* We bound the number of times we retry CMPXCHG on memory locations
|
||||
* that we share with a guest OS. The reason is that the guest can modify
|
||||
* that location at a higher rate than we can read-modify-CMPXCHG, so
|
||||
* the guest could cause us to livelock. There are a few cases
|
||||
* where it is valid for the guest to race our updates (e.g., to change
|
||||
* the GTF_readonly flag), so we allow a few retries before failing.
|
||||
* We bound the number of times we retry CMPXCHG on memory locations that
|
||||
* we share with a guest OS. The reason is that the guest can modify that
|
||||
* location at a higher rate than we can read-modify-CMPXCHG, so the guest
|
||||
* could cause us to livelock. There are a few cases where it is valid for
|
||||
* the guest to race our updates (e.g., to change the GTF_readonly flag),
|
||||
* so we allow a few retries before failing.
|
||||
*/
|
||||
int retries = 0;
|
||||
|
||||
@@ -94,21 +79,18 @@ gnttab_update_pin_status(
|
||||
/* Bitwise-OR avoids short-circuiting which screws control flow. */
|
||||
if ( unlikely(__get_user(dom, &uop->dom) |
|
||||
__get_user(ref, &uop->ref) |
|
||||
__get_user(pin_flags, &uop->pin_flags)) )
|
||||
__get_user(flags, &uop->flags)) )
|
||||
{
|
||||
DPRINTK("Fault while reading gnttab_update_pin_status_t.\n");
|
||||
return -EFAULT;
|
||||
DPRINTK("Fault while reading gnttab_map_grant_ref_t.\n");
|
||||
return; /* don't set status */
|
||||
}
|
||||
|
||||
pin_flags &= (GNTPIN_dev_accessible |
|
||||
GNTPIN_host_accessible |
|
||||
GNTPIN_readonly);
|
||||
|
||||
if ( unlikely(ref >= NR_GRANT_ENTRIES) ||
|
||||
unlikely(pin_flags == GNTPIN_readonly) )
|
||||
unlikely((flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
|
||||
{
|
||||
DPRINTK("Bad ref (%d) or flags (%x).\n", ref, pin_flags);
|
||||
return -EINVAL;
|
||||
DPRINTK("Bad ref (%d) or flags (%x).\n", ref, flags);
|
||||
(void)__put_user(GNTST_bad_gntref, &uop->handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
|
||||
@@ -117,19 +99,25 @@ gnttab_update_pin_status(
|
||||
if ( rd != NULL )
|
||||
put_domain(rd);
|
||||
DPRINTK("Could not find domain %d\n", dom);
|
||||
return -ESRCH;
|
||||
(void)__put_user(GNTST_bad_domain, &uop->handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) )
|
||||
{
|
||||
put_domain(rd);
|
||||
DPRINTK("No more map handles available\n");
|
||||
(void)__put_user(GNTST_no_device_space, &uop->handle);
|
||||
return;
|
||||
}
|
||||
|
||||
act = &rd->grant_table->active[ref];
|
||||
sha = &rd->grant_table->shared[ref];
|
||||
|
||||
spin_lock(&rd->grant_table->lock);
|
||||
|
||||
if ( act->status == 0 )
|
||||
|
||||
if ( act->pin == 0 )
|
||||
{
|
||||
if ( unlikely(pin_flags == 0) )
|
||||
goto out;
|
||||
|
||||
/* CASE 1: Activating a previously inactive entry. */
|
||||
|
||||
sflags = sha->flags;
|
||||
@@ -141,7 +129,7 @@ gnttab_update_pin_status(
|
||||
|
||||
if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) ||
|
||||
unlikely(sdom != ld->domain) )
|
||||
PIN_FAIL(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
|
||||
sflags, sdom, ld->domain);
|
||||
|
||||
@@ -150,11 +138,11 @@ gnttab_update_pin_status(
|
||||
prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags;
|
||||
|
||||
new_scombo = scombo | GTF_reading;
|
||||
if ( !(pin_flags & GNTPIN_readonly) )
|
||||
if ( !(flags & GNTMAP_readonly) )
|
||||
{
|
||||
new_scombo |= GTF_writing;
|
||||
if ( unlikely(sflags & GTF_readonly) )
|
||||
PIN_FAIL(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Attempt to write-pin a r/o grant entry.\n");
|
||||
}
|
||||
|
||||
@@ -162,7 +150,7 @@ gnttab_update_pin_status(
|
||||
if ( unlikely(cmpxchg_user((u32 *)&sha->flags,
|
||||
prev_scombo,
|
||||
new_scombo)) )
|
||||
PIN_FAIL(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Fault while modifying shared flags and domid.\n");
|
||||
|
||||
/* Did the combined update work (did we see what we expected?). */
|
||||
@@ -170,7 +158,7 @@ gnttab_update_pin_status(
|
||||
break;
|
||||
|
||||
if ( retries++ == 4 )
|
||||
PIN_FAIL(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Shared grant entry is unstable.\n");
|
||||
|
||||
/* Didn't see what we expected. Split out the seen flags & dom. */
|
||||
@@ -182,140 +170,226 @@ gnttab_update_pin_status(
|
||||
/* rmb(); */ /* not on x86 */
|
||||
frame = sha->frame;
|
||||
if ( unlikely(!pfn_is_ram(frame)) ||
|
||||
unlikely(!((pin_flags & GNTPIN_readonly) ?
|
||||
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(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Could not pin the granted frame!\n");
|
||||
}
|
||||
|
||||
act->status = pin_flags;
|
||||
act->domid = sdom;
|
||||
act->frame = frame;
|
||||
|
||||
make_entry_mappable(rd->grant_table, act);
|
||||
}
|
||||
else if ( pin_flags == 0 )
|
||||
{
|
||||
/* CASE 2: Deactivating a previously active entry. */
|
||||
|
||||
if ( unlikely((act->status &
|
||||
(GNTPIN_wmap_mask|GNTPIN_rmap_mask)) != 0) )
|
||||
PIN_FAIL(EINVAL,
|
||||
"Attempt to deactiv a mapped g.e. (%x)\n", act->status);
|
||||
|
||||
frame = act->frame;
|
||||
if ( !(act->status & GNTPIN_readonly) )
|
||||
put_page_type(&frame_table[frame]);
|
||||
put_page(&frame_table[frame]);
|
||||
|
||||
act->status = 0;
|
||||
make_entry_unmappable(rd->grant_table, act);
|
||||
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
if ( flags & GNTMAP_device_map )
|
||||
act->pin += (flags & GNTMAP_readonly) ?
|
||||
GNTPIN_devr_inc : GNTPIN_devw_inc;
|
||||
if ( flags & GNTMAP_host_map )
|
||||
act->pin += (flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
act->domid = sdom;
|
||||
act->frame = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* CASE 3: Active modications to an already active entry. */
|
||||
/* CASE 2: Active modications to an already active entry. */
|
||||
|
||||
/*
|
||||
* Check mapping counts up front, as necessary.
|
||||
* After this compound check, the operation cannot fail.
|
||||
* A cheesy check for possible pin-count overflow.
|
||||
* A more accurate check cannot be done with a single comparison.
|
||||
*/
|
||||
if ( ((pin_flags & (GNTPIN_readonly|GNTPIN_host_accessible)) !=
|
||||
GNTPIN_host_accessible) &&
|
||||
(unlikely((act->status & GNTPIN_wmap_mask) != 0) ||
|
||||
(((pin_flags & GNTPIN_host_accessible) == 0) &&
|
||||
unlikely((act->status & GNTPIN_rmap_mask) != 0))) )
|
||||
PIN_FAIL(EINVAL,
|
||||
"Attempt to reduce pinning of a mapped g.e. (%x,%x)\n",
|
||||
pin_flags, act->status);
|
||||
if ( (act->pin & 0x80808080U) != 0 )
|
||||
PIN_FAIL(ENOSPC, "Risk of counter overflow %08x\n", act->pin);
|
||||
|
||||
/* Check for changes to host accessibility. */
|
||||
if ( pin_flags & GNTPIN_host_accessible )
|
||||
if ( !(flags & GNTMAP_readonly) &&
|
||||
!((sflags = sha->flags) & GTF_writing) )
|
||||
{
|
||||
if ( !(act->status & GNTPIN_host_accessible) )
|
||||
make_entry_mappable(rd->grant_table, act);
|
||||
}
|
||||
else if ( act->status & GNTPIN_host_accessible )
|
||||
make_entry_unmappable(rd->grant_table, act);
|
||||
|
||||
/* Check for changes to write accessibility. */
|
||||
if ( pin_flags & GNTPIN_readonly )
|
||||
{
|
||||
if ( !(act->status & GNTPIN_readonly) )
|
||||
{
|
||||
put_page_type(&frame_table[act->frame]);
|
||||
check_tlb_flush(act);
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
}
|
||||
}
|
||||
else if ( act->status & GNTPIN_readonly )
|
||||
{
|
||||
sflags = sha->flags;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
u16 prev_sflags;
|
||||
|
||||
if ( unlikely(sflags & GTF_readonly) )
|
||||
PIN_FAIL(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Attempt to write-pin a r/o grant entry.\n");
|
||||
|
||||
if ( unlikely(!get_page_type(&frame_table[act->frame],
|
||||
PGT_writable_page)) )
|
||||
PIN_FAIL(EINVAL,
|
||||
"Attempt to write-pin a unwritable page.\n");
|
||||
|
||||
prev_sflags = sflags;
|
||||
|
||||
/* NB. prev_sflags is updated in place to seen value. */
|
||||
if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags,
|
||||
prev_sflags | GTF_writing)) )
|
||||
PIN_FAIL(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Fault while modifying shared flags.\n");
|
||||
|
||||
if ( likely(prev_sflags == sflags) )
|
||||
break;
|
||||
|
||||
if ( retries++ == 4 )
|
||||
PIN_FAIL(EINVAL,
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Shared grant entry is unstable.\n");
|
||||
|
||||
sflags = prev_sflags;
|
||||
}
|
||||
|
||||
if ( unlikely(!get_page_type(&frame_table[act->frame],
|
||||
PGT_writable_page)) )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Attempt to write-pin a unwritable page.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Update status word -- this includes device accessibility. */
|
||||
act->status &= ~(GNTPIN_dev_accessible |
|
||||
GNTPIN_host_accessible |
|
||||
GNTPIN_readonly);
|
||||
act->status |= pin_flags;
|
||||
if ( flags & GNTMAP_device_map )
|
||||
act->pin += (flags & GNTMAP_readonly) ?
|
||||
GNTPIN_devr_inc : GNTPIN_devw_inc;
|
||||
if ( flags & GNTMAP_host_map )
|
||||
act->pin += (flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
}
|
||||
|
||||
/* Unchecked and unconditional. */
|
||||
(void)__put_user(act->frame, &uop->dev_bus_addr);
|
||||
(void)__put_user(act->frame, &uop->host_phys_addr);
|
||||
ld->grant_table->maptrack[handle].domid = dom;
|
||||
ld->grant_table->maptrack[handle].ref_and_flags =
|
||||
(ref << MAPTRACK_REF_SHIFT) | (flags & MAPTRACK_GNTMAP_MASK);
|
||||
|
||||
/* Unchecked and unconditional. */
|
||||
(void)__put_user(handle, &uop->handle);
|
||||
(void)__put_user(act->frame, &uop->dev_bus_addr);
|
||||
|
||||
out:
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
put_domain(rd);
|
||||
return rc;
|
||||
return;
|
||||
|
||||
fail:
|
||||
(void)__put_user(rc, &uop->handle);
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
put_domain(rd);
|
||||
put_maptrack_handle(ld->grant_table, handle);
|
||||
}
|
||||
|
||||
static long
|
||||
gnttab_map_grant_ref(
|
||||
gnttab_map_grant_ref_t *uop, unsigned int count)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < count; i++ )
|
||||
__gnttab_map_grant_ref(&uop[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
__gnttab_unmap_grant_ref(
|
||||
gnttab_unmap_grant_ref_t *uop)
|
||||
{
|
||||
domid_t dom;
|
||||
grant_ref_t ref;
|
||||
u16 handle;
|
||||
struct domain *ld, *rd;
|
||||
|
||||
active_grant_entry_t *act;
|
||||
grant_entry_t *sha;
|
||||
grant_mapping_t *map;
|
||||
s16 rc = 0;
|
||||
unsigned long frame, virt;
|
||||
|
||||
ld = current;
|
||||
|
||||
/* Bitwise-OR avoids short-circuiting which screws control flow. */
|
||||
if ( unlikely(__get_user(virt, &uop->host_virt_addr) |
|
||||
__get_user(frame, &uop->dev_bus_addr) |
|
||||
__get_user(handle, &uop->handle)) )
|
||||
{
|
||||
DPRINTK("Fault while reading gnttab_unmap_grant_ref_t.\n");
|
||||
return; /* don't set status */
|
||||
}
|
||||
|
||||
map = &ld->grant_table->maptrack[handle];
|
||||
|
||||
if ( unlikely(handle >= NR_MAPTRACK_ENTRIES) ||
|
||||
unlikely(!(map->ref_and_flags & MAPTRACK_GNTMAP_MASK)) )
|
||||
{
|
||||
DPRINTK("Bad handle (%d).\n", handle);
|
||||
(void)__put_user(GNTST_bad_handle, &uop->status);
|
||||
return;
|
||||
}
|
||||
|
||||
dom = map->domid;
|
||||
ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT;
|
||||
|
||||
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
|
||||
unlikely(ld == rd) )
|
||||
{
|
||||
if ( rd != NULL )
|
||||
put_domain(rd);
|
||||
DPRINTK("Could not find domain %d\n", dom);
|
||||
(void)__put_user(GNTST_bad_domain, &uop->status);
|
||||
return;
|
||||
}
|
||||
|
||||
act = &rd->grant_table->active[ref];
|
||||
sha = &rd->grant_table->shared[ref];
|
||||
|
||||
spin_lock(&rd->grant_table->lock);
|
||||
|
||||
if ( frame != 0 )
|
||||
{
|
||||
if ( unlikely(frame != act->frame) )
|
||||
PIN_FAIL(GNTST_general_error,
|
||||
"Bad frame number doesn't match gntref.\n");
|
||||
if ( map->ref_and_flags & GNTMAP_device_map )
|
||||
act->pin -= (map->ref_and_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_devr_inc : GNTPIN_devw_inc;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame = act->frame;
|
||||
}
|
||||
|
||||
if ( (virt != 0) && (map->ref_and_flags & GNTMAP_host_map) )
|
||||
{
|
||||
act->pin -= (map->ref_and_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
}
|
||||
|
||||
if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
|
||||
!(map->ref_and_flags & GNTMAP_readonly) )
|
||||
{
|
||||
put_page_type(&frame_table[frame]);
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
}
|
||||
|
||||
if ( act->pin == 0 )
|
||||
{
|
||||
put_page(&frame_table[frame]);
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
}
|
||||
|
||||
fail:
|
||||
(void)__put_user(rc, &uop->status);
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
put_domain(rd);
|
||||
}
|
||||
|
||||
static long
|
||||
gnttab_unmap_grant_ref(
|
||||
gnttab_unmap_grant_ref_t *uop, unsigned int count)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < count; i++ )
|
||||
__gnttab_unmap_grant_ref(&uop[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
gnttab_setup_table(
|
||||
gnttab_setup_table_t *uop)
|
||||
gnttab_setup_table_t *uop, unsigned int count)
|
||||
{
|
||||
gnttab_setup_table_t op;
|
||||
struct domain *d;
|
||||
|
||||
if ( unlikely(__copy_from_user(&op, uop, sizeof(op)) != 0) )
|
||||
if ( count != 1 )
|
||||
return -EINVAL;
|
||||
|
||||
if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) )
|
||||
{
|
||||
DPRINTK("Fault while reading gnttab_setup_table_t.\n");
|
||||
return -EFAULT;
|
||||
@@ -324,29 +398,33 @@ gnttab_setup_table(
|
||||
if ( unlikely(op.nr_frames > 1) )
|
||||
{
|
||||
DPRINTK("Xen only supports one grant-table frame per domain.\n");
|
||||
return -EINVAL;
|
||||
(void)put_user(GNTST_general_error, &uop->status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( op.dom == DOMID_SELF )
|
||||
{
|
||||
op.dom = current->domain;
|
||||
}
|
||||
else if ( unlikely(!IS_PRIV(current)) )
|
||||
{
|
||||
(void)put_user(GNTST_permission_denied, &uop->status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) )
|
||||
{
|
||||
DPRINTK("Bad domid %d.\n", op.dom);
|
||||
return -ESRCH;
|
||||
(void)put_user(GNTST_bad_domain, &uop->status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( op.nr_frames == 1 )
|
||||
{
|
||||
ASSERT(d->grant_table != NULL);
|
||||
|
||||
if ( unlikely(put_user(virt_to_phys(d->grant_table) >> PAGE_SHIFT,
|
||||
&op.frame_list[0])) )
|
||||
{
|
||||
DPRINTK("Fault while writing frame list.\n");
|
||||
put_domain(d);
|
||||
return -EFAULT;
|
||||
}
|
||||
(void)put_user(GNTST_okay, &uop->status);
|
||||
(void)put_user(virt_to_phys(d->grant_table) >> PAGE_SHIFT,
|
||||
&uop->frame_list[0]);
|
||||
}
|
||||
|
||||
put_domain(d);
|
||||
@@ -355,22 +433,29 @@ gnttab_setup_table(
|
||||
|
||||
long
|
||||
do_grant_table_op(
|
||||
gnttab_op_t *uop)
|
||||
unsigned int cmd, void *uop, unsigned int count)
|
||||
{
|
||||
long rc;
|
||||
u32 cmd;
|
||||
|
||||
if ( unlikely(!access_ok(VERIFY_WRITE, uop, sizeof(*uop))) ||
|
||||
unlikely(__get_user(cmd, &uop->cmd)) )
|
||||
return -EFAULT;
|
||||
if ( count > 512 )
|
||||
return -EINVAL;
|
||||
|
||||
switch ( cmd )
|
||||
{
|
||||
case GNTTABOP_update_pin_status:
|
||||
rc = gnttab_update_pin_status(&uop->u.update_pin_status);
|
||||
case GNTTABOP_map_grant_ref:
|
||||
if ( unlikely(!access_ok(VERIFY_WRITE, uop,
|
||||
count * sizeof(gnttab_map_grant_ref_t))) )
|
||||
return -EFAULT;
|
||||
rc = gnttab_map_grant_ref((gnttab_map_grant_ref_t *)uop, count);
|
||||
break;
|
||||
case GNTTABOP_unmap_grant_ref:
|
||||
if ( unlikely(!access_ok(VERIFY_WRITE, uop,
|
||||
count * sizeof(gnttab_unmap_grant_ref_t))) )
|
||||
return -EFAULT;
|
||||
rc = gnttab_unmap_grant_ref((gnttab_unmap_grant_ref_t *)uop, count);
|
||||
break;
|
||||
case GNTTABOP_setup_table:
|
||||
rc = gnttab_setup_table(&uop->u.setup_table);
|
||||
rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
@@ -381,66 +466,10 @@ do_grant_table_op(
|
||||
}
|
||||
|
||||
int
|
||||
gnttab_try_map(
|
||||
struct domain *rd, struct domain *ld, unsigned long frame, int op)
|
||||
gnttab_check_unmap(
|
||||
struct domain *rd, struct domain *ld, unsigned long frame, int readonly)
|
||||
{
|
||||
grant_table_t *t;
|
||||
active_grant_entry_t *a;
|
||||
u16 *ph, h;
|
||||
|
||||
if ( unlikely((t = rd->grant_table) == NULL) )
|
||||
return 0;
|
||||
|
||||
spin_lock(&t->lock);
|
||||
|
||||
ph = &t->maphash[GNT_MAPHASH(frame)];
|
||||
while ( (h = *ph) != GNT_MAPHASH_INVALID )
|
||||
{
|
||||
if ( (a = &t->active[*ph])->frame != frame )
|
||||
goto found;
|
||||
ph = &a->next;
|
||||
}
|
||||
|
||||
fail:
|
||||
spin_unlock(&t->lock);
|
||||
return 0;
|
||||
|
||||
found:
|
||||
if ( !(a->status & GNTPIN_host_accessible) )
|
||||
goto fail;
|
||||
|
||||
switch ( op )
|
||||
{
|
||||
case GNTTAB_MAP_RO:
|
||||
if ( (a->status & GNTPIN_rmap_mask) == GNTPIN_rmap_mask )
|
||||
goto fail;
|
||||
a->status += 1 << GNTPIN_rmap_shift;
|
||||
break;
|
||||
|
||||
case GNTTAB_MAP_RW:
|
||||
if ( (a->status & GNTPIN_wmap_mask) == GNTPIN_wmap_mask )
|
||||
goto fail;
|
||||
a->status += 1 << GNTPIN_wmap_shift;
|
||||
break;
|
||||
|
||||
case GNTTAB_UNMAP_RO:
|
||||
if ( (a->status & GNTPIN_rmap_mask) == 0 )
|
||||
goto fail;
|
||||
a->status -= 1 << GNTPIN_rmap_shift;
|
||||
break;
|
||||
|
||||
case GNTTAB_UNMAP_RW:
|
||||
if ( (a->status & GNTPIN_wmap_mask) == 0 )
|
||||
goto fail;
|
||||
a->status -= 1 << GNTPIN_wmap_shift;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
spin_unlock(&t->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -529,21 +558,24 @@ grant_table_create(
|
||||
grant_table_t *t;
|
||||
int i;
|
||||
|
||||
if ( (t = xmalloc(sizeof(grant_table_t))) == NULL )
|
||||
if ( (t = xmalloc(sizeof(*t))) == NULL )
|
||||
goto no_mem;
|
||||
|
||||
/* Simple stuff. */
|
||||
t->shared = NULL;
|
||||
t->active = NULL;
|
||||
memset(t, 0, sizeof(*t));
|
||||
spin_lock_init(&t->lock);
|
||||
for ( i = 0; i < GNT_MAPHASH_SZ; i++ )
|
||||
t->maphash[i] = GNT_MAPHASH_INVALID;
|
||||
|
||||
/* Active grant-table page. */
|
||||
if ( (t->active = xmalloc(sizeof(active_grant_entry_t) *
|
||||
NR_GRANT_ENTRIES)) == NULL )
|
||||
goto no_mem;
|
||||
|
||||
if ( (t->maptrack = (void *)alloc_xenheap_page()) == NULL )
|
||||
goto no_mem;
|
||||
memset(t->maptrack, 0, PAGE_SIZE);
|
||||
for ( i = 0; i < NR_MAPTRACK_ENTRIES; i++ )
|
||||
t->maptrack[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT;
|
||||
|
||||
/* Set up shared grant-table page. */
|
||||
if ( (t->shared = (void *)alloc_xenheap_page()) == NULL )
|
||||
goto no_mem;
|
||||
@@ -560,6 +592,8 @@ grant_table_create(
|
||||
{
|
||||
if ( t->active != NULL )
|
||||
xfree(t->active);
|
||||
if ( t->maptrack != NULL )
|
||||
free_xenheap_page((unsigned long)t->maptrack);
|
||||
xfree(t);
|
||||
}
|
||||
return -ENOMEM;
|
||||
@@ -576,6 +610,7 @@ grant_table_destroy(
|
||||
/* Free memory relating to this grant table. */
|
||||
d->grant_table = NULL;
|
||||
free_xenheap_page((unsigned long)t->shared);
|
||||
free_xenheap_page((unsigned long)t->maptrack);
|
||||
xfree(t->active);
|
||||
xfree(t);
|
||||
}
|
||||
|
||||
+1
-11
@@ -297,19 +297,9 @@ void cmain(multiboot_info_t *mbi)
|
||||
xmem_cache_init();
|
||||
xmem_cache_sizes_init(max_page);
|
||||
|
||||
/*
|
||||
* Create a domain-structure allocator. The SLAB_NO_REAP flag is essential!
|
||||
* This is because in some situations a domain's reference count will be
|
||||
* incremented by someone with no other handle on the structure -- this is
|
||||
* inherently racey because the struct could be freed by the time that the
|
||||
* count is incremented. By specifying 'no-reap' we ensure that, worst
|
||||
* case, they increment some other domain's count, rather than corrupting
|
||||
* a random field in a random structure!
|
||||
* See, for example, arch/x86/memory.c:get_page_from_l1e().
|
||||
*/
|
||||
domain_struct_cachep = xmem_cache_create(
|
||||
"domain_cache", sizeof(struct domain),
|
||||
0, SLAB_HWCACHE_ALIGN | SLAB_NO_REAP, NULL, NULL);
|
||||
0, SLAB_HWCACHE_ALIGN, NULL, NULL);
|
||||
if ( domain_struct_cachep == NULL )
|
||||
panic("No slab cache for task structs.");
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ unsigned long alloc_xenheap_pages(int order)
|
||||
|
||||
for ( i = 0; i < (1 << order); i++ )
|
||||
{
|
||||
pg[i].count_info = PGC_always_set;
|
||||
pg[i].count_info = 0;
|
||||
pg[i].u.inuse.domain = NULL;
|
||||
pg[i].u.inuse.type_info = 0;
|
||||
}
|
||||
@@ -384,7 +384,7 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, int order)
|
||||
}
|
||||
}
|
||||
|
||||
pg[i].count_info = PGC_always_set;
|
||||
pg[i].count_info = 0;
|
||||
pg[i].u.inuse.domain = NULL;
|
||||
pg[i].u.inuse.type_info = 0;
|
||||
}
|
||||
|
||||
+14
-17
@@ -70,33 +70,30 @@ struct pfn_info
|
||||
#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)
|
||||
#define PGT_validated (1U<<_PGT_validated)
|
||||
/* Owning guest has pinned this page to its current type? */
|
||||
#define _PGT_pinned 27
|
||||
#define PGT_pinned (1<<_PGT_pinned)
|
||||
#define PGT_pinned (1U<<_PGT_pinned)
|
||||
/* The 10 most significant bits of virt address if this is a page table. */
|
||||
#define PGT_va_shift 17
|
||||
#define PGT_va_mask (((1<<10)-1)<<PGT_va_shift)
|
||||
#define PGT_va_mask (((1U<<10)-1)<<PGT_va_shift)
|
||||
/* Is the back pointer still mutable (i.e. not fixed yet)? */
|
||||
#define PGT_va_mutable (((1<<10)-1)<<PGT_va_shift)
|
||||
#define PGT_va_mutable (((1U<<10)-1)<<PGT_va_shift)
|
||||
/* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
|
||||
#define PGT_va_unknown (((1<<10)-2)<<PGT_va_shift)
|
||||
#define PGT_va_unknown (((1U<<10)-2)<<PGT_va_shift)
|
||||
/* 17-bit count of uses of this frame as its current type. */
|
||||
#define PGT_count_mask ((1<<17)-1)
|
||||
#define PGT_count_mask ((1U<<17)-1)
|
||||
|
||||
/* Cleared when the owning guest 'frees' this page. */
|
||||
#define _PGC_allocated 31
|
||||
#define PGC_allocated (1<<_PGC_allocated)
|
||||
/* This bit is always set, guaranteeing that the count word is never zero. */
|
||||
#define _PGC_always_set 30
|
||||
#define PGC_always_set (1<<_PGC_always_set)
|
||||
/* 30-bit count of references to this frame. */
|
||||
#define PGC_count_mask ((1<<30)-1)
|
||||
#define _PGC_allocated 31
|
||||
#define PGC_allocated (1U<<_PGC_allocated)
|
||||
/* 31-bit count of references to this frame. */
|
||||
#define PGC_count_mask ((1U<<31)-1)
|
||||
|
||||
/* 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 PageSlab(page) (1)
|
||||
#define PageSetSlab(page) ((void)0)
|
||||
#define PageClearSlab(page) ((void)0)
|
||||
|
||||
#define IS_XEN_HEAP_FRAME(_pfn) (page_to_phys(_pfn) < xenheap_phys_end)
|
||||
|
||||
@@ -108,7 +105,7 @@ struct pfn_info
|
||||
wmb(); /* install valid domain ptr before updating refcnt. */ \
|
||||
spin_lock(&(_dom)->page_alloc_lock); \
|
||||
/* _dom holds an allocation reference */ \
|
||||
ASSERT((_pfn)->count_info == PGC_always_set); \
|
||||
ASSERT((_pfn)->count_info == 0); \
|
||||
(_pfn)->count_info |= PGC_allocated | 1; \
|
||||
if ( unlikely((_dom)->xenheap_pages++ == 0) ) \
|
||||
get_knownalive_domain(_dom); \
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
*
|
||||
* Introducing a valid entry into the grant table:
|
||||
* 1. Write ent->domid.
|
||||
* 2. Write ent->frame (to zero if installing GTF_accept_transfer).
|
||||
* 2. Write ent->frame:
|
||||
* GTF_permit_access: Frame to which access is permitted.
|
||||
* GTF_accept_transfer: Pseudo-phys frame slot being filled by new
|
||||
* frame, or zero if none.
|
||||
* 3. Write memory barrier (WMB).
|
||||
* 4. Write ent->flags, inc. valid type.
|
||||
*
|
||||
@@ -49,10 +52,11 @@
|
||||
* [*] If GTF_transfer_committed is set then the grant entry is 'committed'.
|
||||
* The guest must /not/ modify the grant entry until the address of the
|
||||
* transferred frame is written. It is safe for the guest to spin waiting
|
||||
* for this to occur (detect by observing non-zero value in ent->frame).
|
||||
* for this to occur (detect by observing GTF_transfer_completed in
|
||||
* ent->flags).
|
||||
*
|
||||
* Invalidating a committed GTF_accept_transfer entry:
|
||||
* 1. Wait for ent->frame != 0.
|
||||
* 1. Wait for (ent->flags & GTF_transfer_completed).
|
||||
*
|
||||
* Changing a GTF_permit_access from writable to read-only:
|
||||
* Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing.
|
||||
@@ -86,10 +90,10 @@ typedef struct {
|
||||
* GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
|
||||
* to this guest. Xen writes the page number to @frame.
|
||||
*/
|
||||
#define GTF_invalid (0<<0)
|
||||
#define GTF_permit_access (1<<0)
|
||||
#define GTF_accept_transfer (2<<0)
|
||||
#define GTF_type_mask (3<<0)
|
||||
#define GTF_invalid (0U<<0)
|
||||
#define GTF_permit_access (1U<<0)
|
||||
#define GTF_accept_transfer (2U<<0)
|
||||
#define GTF_type_mask (3U<<0)
|
||||
|
||||
/*
|
||||
* Subflags for GTF_permit_access.
|
||||
@@ -98,23 +102,26 @@ typedef struct {
|
||||
* GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
|
||||
*/
|
||||
#define _GTF_readonly (2)
|
||||
#define GTF_readonly (1<<_GTF_readonly)
|
||||
#define GTF_readonly (1U<<_GTF_readonly)
|
||||
#define _GTF_reading (3)
|
||||
#define GTF_reading (1<<_GTF_reading)
|
||||
#define GTF_reading (1U<<_GTF_reading)
|
||||
#define _GTF_writing (4)
|
||||
#define GTF_writing (1<<_GTF_writing)
|
||||
#define GTF_writing (1U<<_GTF_writing)
|
||||
|
||||
/*
|
||||
* Subflags for GTF_accept_transfer:
|
||||
* GTF_transfer_committed: Xen sets this flag to indicate that it is committed
|
||||
* to transferring ownership of a page frame. When a guest sees this flag
|
||||
* it must /not/ modify the grant entry until the address of the
|
||||
* transferred frame is written into the entry.
|
||||
* NB. It is safe for the guest to spin-wait on the frame address:
|
||||
* Xen will always write the frame address in a timely manner.
|
||||
* it must /not/ modify the grant entry until GTF_transfer_completed is
|
||||
* set by Xen.
|
||||
* GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
|
||||
* after reading GTF_transfer_committed. Xen will always write the frame
|
||||
* address, followed by ORing this flag, in a timely manner.
|
||||
*/
|
||||
#define _GTF_transfer_committed (2)
|
||||
#define GTF_transfer_committed (1<<_GTF_transfer_committed)
|
||||
#define GTF_transfer_committed (1U<<_GTF_transfer_committed)
|
||||
#define _GTF_transfer_completed (3)
|
||||
#define GTF_transfer_completed (1U<<_GTF_transfer_completed)
|
||||
|
||||
|
||||
/***********************************
|
||||
@@ -127,28 +134,56 @@ typedef struct {
|
||||
typedef u16 grant_ref_t;
|
||||
|
||||
/*
|
||||
* GNTTABOP_update_pin_status: Change the pin status of of <dom>'s grant entry
|
||||
* with reference <ref>.
|
||||
* GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
|
||||
* by devices and/or host CPUs. If successful, <handle> is a tracking number
|
||||
* that must be presented later to destroy the mapping(s). On error, <handle>
|
||||
* is a negative status code.
|
||||
* NOTES:
|
||||
* 1. If GNTPIN_dev_accessible is specified then <dev_bus_addr> is the address
|
||||
* 1. If GNTPIN_map_for_dev is specified then <dev_bus_addr> is the address
|
||||
* via which I/O devices may access the granted frame.
|
||||
* 2. If GNTPIN_host_accessible is specified then <host_phys_addr> is the
|
||||
* physical address of the frame, which may be mapped into the caller's
|
||||
* page tables.
|
||||
* 2. If GNTPIN_map_for_host is specified then a mapping will be added at
|
||||
* virtual address <host_virt_addr> in the current address space.
|
||||
* 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
|
||||
* host mapping is destroyed by other means then it is *NOT* guaranteed
|
||||
* to be accounted to the correct grant reference!
|
||||
*/
|
||||
#define GNTTABOP_update_pin_status 0
|
||||
#define GNTTABOP_map_grant_ref 0
|
||||
typedef struct {
|
||||
/* IN parameters. */
|
||||
domid_t dom; /* 0 */
|
||||
grant_ref_t ref; /* 2 */
|
||||
u16 pin_flags; /* 4 */
|
||||
u16 __pad; /* 6 */
|
||||
memory_t host_virt_addr; /* 0 */
|
||||
MEMORY_PADDING;
|
||||
domid_t dom; /* 8 */
|
||||
grant_ref_t ref; /* 10 */
|
||||
u16 flags; /* 12: GNTMAP_* */
|
||||
/* OUT parameters. */
|
||||
s16 handle; /* 14: +ve: handle; -ve: GNTST_* */
|
||||
memory_t dev_bus_addr; /* 16 */
|
||||
MEMORY_PADDING;
|
||||
} PACKED gnttab_map_grant_ref_t; /* 24 bytes */
|
||||
|
||||
/*
|
||||
* GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
|
||||
* tracked by <handle>. If <host_virt_addr> or <dev_bus_addr> is zero, that
|
||||
* field is ignored. If non-zero, they must refer to a device/host mapping
|
||||
* that is tracked by <handle>
|
||||
* NOTES:
|
||||
* 1. The call may fail in an undefined manner if either mapping is not
|
||||
* tracked by <handle>.
|
||||
* 3. After executing a batch of unmaps, it is guaranteed that no stale
|
||||
* mappings will remain in the device or host TLBs.
|
||||
*/
|
||||
#define GNTTABOP_unmap_grant_ref 1
|
||||
typedef struct {
|
||||
/* IN parameters. */
|
||||
memory_t host_virt_addr; /* 0 */
|
||||
MEMORY_PADDING;
|
||||
memory_t dev_bus_addr; /* 8 */
|
||||
MEMORY_PADDING;
|
||||
memory_t host_phys_addr; /* 12 */
|
||||
MEMORY_PADDING;
|
||||
} PACKED gnttab_update_pin_status_t; /* 16 bytes */
|
||||
u16 handle; /* 16 */
|
||||
/* OUT parameters. */
|
||||
s16 status; /* 18: GNTST_* */
|
||||
u32 __pad;
|
||||
} PACKED gnttab_unmap_grant_ref_t; /* 24 bytes */
|
||||
|
||||
/*
|
||||
* GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
|
||||
@@ -159,38 +194,58 @@ typedef struct {
|
||||
* 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
|
||||
* 3. Xen may not support more than a single grant-table page per domain.
|
||||
*/
|
||||
#define GNTTABOP_setup_table 1
|
||||
#define GNTTABOP_setup_table 2
|
||||
typedef struct {
|
||||
/* IN parameters. */
|
||||
domid_t dom; /* 0 */
|
||||
u16 nr_frames; /* 2 */
|
||||
u32 __pad;
|
||||
u16 __pad;
|
||||
/* OUT parameters. */
|
||||
s16 status; /* 6: GNTST_* */
|
||||
unsigned long *frame_list; /* 8 */
|
||||
MEMORY_PADDING;
|
||||
} PACKED gnttab_setup_table_t; /* 16 bytes */
|
||||
|
||||
typedef struct {
|
||||
u32 cmd; /* GNTTABOP_* */ /* 0 */
|
||||
u32 __reserved; /* 4 */
|
||||
union { /* 8 */
|
||||
gnttab_update_pin_status_t update_pin_status;
|
||||
gnttab_setup_table_t setup_table;
|
||||
u8 __dummy[16];
|
||||
} PACKED u;
|
||||
} PACKED gnttab_op_t; /* 24 bytes */
|
||||
/*
|
||||
* Bitfield values for update_pin_status.flags.
|
||||
*/
|
||||
/* Map the grant entry for access by I/O devices. */
|
||||
#define _GNTMAP_device_map (0)
|
||||
#define GNTMAP_device_map (1<<_GNTMAP_device_map)
|
||||
/* Map the grant entry for access by host CPUs. */
|
||||
#define _GNTMAP_host_map (1)
|
||||
#define GNTMAP_host_map (1<<_GNTMAP_host_map)
|
||||
/* Accesses to the granted frame will be restricted to read-only access. */
|
||||
#define _GNTMAP_readonly (2)
|
||||
#define GNTMAP_readonly (1<<_GNTMAP_readonly)
|
||||
/*
|
||||
* GNTMAP_host_map subflag:
|
||||
* 0 => The host mapping is usable only by the guest OS.
|
||||
* 1 => The host mapping is usable by guest OS + current application.
|
||||
*/
|
||||
#define _GNTMAP_application_map (3)
|
||||
#define GNTMAP_application_map (1<<_GNTMAP_application_map)
|
||||
|
||||
/*
|
||||
* Bitfield values for <pin_flags>.
|
||||
* Values for error status returns. All errors are -ve.
|
||||
*/
|
||||
/* Pin the grant entry for access by I/O devices. */
|
||||
#define _GNTPIN_dev_accessible (0)
|
||||
#define GNTPIN_dev_accessible (1<<_GNTPIN_dev_accessible)
|
||||
/* Pin the grant entry for access by host CPUs. */
|
||||
#define _GNTPIN_host_accessible (1)
|
||||
#define GNTPIN_host_accessible (1<<_GNTPIN_host_accessible)
|
||||
/* Accesses to the granted frame will be restricted to read-only access. */
|
||||
#define _GNTPIN_readonly (2)
|
||||
#define GNTPIN_readonly (1<<_GNTPIN_readonly)
|
||||
#define GNTST_okay (0)
|
||||
#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 GNTTABOP_error_msgs { \
|
||||
"okay", \
|
||||
"undefined error", \
|
||||
"unrecognised domain id", \
|
||||
"invalid grant reference", \
|
||||
"invalid mapping handle", \
|
||||
"no spare translation slot in the I/O MMU", \
|
||||
"permission denied" \
|
||||
}
|
||||
|
||||
|
||||
#endif /* __HYPERVISOR_IFS_GRANT_TABLE_H__ */
|
||||
@@ -30,40 +30,53 @@
|
||||
|
||||
/* Active grant entry - used for shadowing GTF_permit_access grants. */
|
||||
typedef struct {
|
||||
u32 status; /* Reference count information. */
|
||||
u32 tlbflush_timestamp; /* Flush avoidance. */
|
||||
u16 next; /* Mapping hash chain. */
|
||||
u32 pin; /* Reference count information. */
|
||||
domid_t domid; /* Domain being granted access. */
|
||||
unsigned long frame; /* Frame being granted. */
|
||||
} active_grant_entry_t;
|
||||
|
||||
/*
|
||||
* Bitfields in active_grant_entry_t:counts.
|
||||
* NB. Some other GNTPIN_xxx definitions are in hypervisor-ifs/grant_table.h.
|
||||
*/
|
||||
/* Count of writable host-CPU mappings. */
|
||||
#define GNTPIN_wmap_shift (4)
|
||||
#define GNTPIN_wmap_mask (0x3FFFU << GNTPIN_wmap_shift)
|
||||
#define GNTPIN_hstw_shift (0)
|
||||
#define GNTPIN_hstw_inc (1 << GNTPIN_hstw_shift)
|
||||
#define GNTPIN_hstw_mask (0xFFU << GNTPIN_hstw_shift)
|
||||
/* Count of read-only host-CPU mappings. */
|
||||
#define GNTPIN_rmap_shift (18)
|
||||
#define GNTPIN_rmap_mask (0x3FFFU << GNTPIN_rmap_shift)
|
||||
|
||||
#define GNT_MAPHASH_SZ (256)
|
||||
#define GNT_MAPHASH(_k) ((_k) & (GNT_MAPHASH_SZ-1))
|
||||
#define GNT_MAPHASH_INVALID (0xFFFFU)
|
||||
#define GNTPIN_hstr_shift (8)
|
||||
#define GNTPIN_hstr_inc (1 << GNTPIN_hstr_shift)
|
||||
#define GNTPIN_hstr_mask (0xFFU << GNTPIN_hstr_shift)
|
||||
/* Count of writable device-bus mappings. */
|
||||
#define GNTPIN_devw_shift (16)
|
||||
#define GNTPIN_devw_inc (1 << GNTPIN_devw_shift)
|
||||
#define GNTPIN_devw_mask (0xFFU << GNTPIN_devw_shift)
|
||||
/* Count of read-only device-bus mappings. */
|
||||
#define GNTPIN_devr_shift (24)
|
||||
#define GNTPIN_devr_inc (1 << GNTPIN_devr_shift)
|
||||
#define GNTPIN_devr_mask (0xFFU << GNTPIN_devr_shift)
|
||||
|
||||
#define NR_GRANT_ENTRIES (PAGE_SIZE / sizeof(grant_entry_t))
|
||||
|
||||
/*
|
||||
* Tracks a mapping of another domain's grant reference. Each domain has a
|
||||
* table of these, indexes into which are returned as a 'mapping handle'.
|
||||
*/
|
||||
typedef struct {
|
||||
u16 ref_and_flags; /* 0-2: GNTMAP_* ; 3-15: grant ref */
|
||||
domid_t domid; /* granting domain */
|
||||
} grant_mapping_t;
|
||||
#define MAPTRACK_GNTMAP_MASK 7
|
||||
#define MAPTRACK_REF_SHIFT 3
|
||||
#define NR_MAPTRACK_ENTRIES (PAGE_SIZE / sizeof(grant_mapping_t))
|
||||
|
||||
/* Per-domain grant information. */
|
||||
typedef struct {
|
||||
/* Shared grant table (see include/hypervisor-ifs/grant_table.h). */
|
||||
grant_entry_t *shared;
|
||||
/* Active grant table. */
|
||||
active_grant_entry_t *active;
|
||||
/* Lock protecting updates to maphash and shared grant table. */
|
||||
/* Mapping tracking table. */
|
||||
grant_mapping_t *maptrack;
|
||||
unsigned int maptrack_head;
|
||||
/* Lock protecting updates to active and shared grant tables. */
|
||||
spinlock_t lock;
|
||||
/* Hash table: frame -> active grant entry. */
|
||||
u16 maphash[GNT_MAPHASH_SZ];
|
||||
} grant_table_t;
|
||||
|
||||
/* Start-of-day system initialisation. */
|
||||
@@ -76,13 +89,9 @@ int grant_table_create(
|
||||
void grant_table_destroy(
|
||||
struct domain *d);
|
||||
|
||||
/* Create/destroy host-CPU mappings via a grant-table entry. */
|
||||
#define GNTTAB_MAP_RO 0
|
||||
#define GNTTAB_MAP_RW 1
|
||||
#define GNTTAB_UNMAP_RO 2
|
||||
#define GNTTAB_UNMAP_RW 3
|
||||
int gnttab_try_map(
|
||||
struct domain *rd, struct domain *ld, unsigned long frame, int op);
|
||||
/* Destroy host-CPU mappings via a grant-table entry. */
|
||||
int gnttab_check_unmap(
|
||||
struct domain *rd, struct domain *ld, unsigned long frame, int readonly);
|
||||
|
||||
/*
|
||||
* Check that the given grant reference (rd,ref) allows 'ld' to transfer
|
||||
|
||||