bitkeeper revision 1.1159.1.99 (412b0f11cFbfdCRdP2-GJYp0ANDfUA)

Merge scramble.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into scramble.cl.cam.ac.uk:/local/scratch/kaf24/xeno
This commit is contained in:
kaf24@scramble.cl.cam.ac.uk committed 2004-08-24 09:49:05 +00:00
commit b480e23d76
32 files changed
+1199 -759

No files matched your search

@@ -115,7 +115,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
void destroy_context(struct mm_struct *mm)
{
if (mm->context.size) {
make_pages_writeable(
make_pages_writable(
mm->context.ldt,
(mm->context.size*LDT_ENTRY_SIZE)/PAGE_SIZE);
flush_page_update_queue();
@@ -648,7 +648,7 @@ void __init trap_init(void)
* ensures this end result (blow away the selector value) without the dangers
* of the normal page-fault handler.
*
* NB. Perhaps this can all go away after we have implemented writeable
* NB. Perhaps this can all go away after we have implemented writable
* page tables. :-)
*/
@@ -111,7 +111,7 @@ static inline void free_pgd_slow(pgd_t *pgd)
kmem_cache_free(pae_pgd_cachep, pgd);
#else
queue_pgd_unpin(__pa(pgd));
__make_page_writeable(pgd);
__make_page_writable(pgd);
free_page((unsigned long)pgd);
#endif
}
@@ -154,7 +154,7 @@ static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
static __inline__ void pte_free_slow(pte_t *pte)
{
queue_pte_unpin(__pa(pte));
__make_page_writeable(pte);
__make_page_writable(pte);
free_page((unsigned long)pte);
}
@@ -302,7 +302,7 @@ static inline void __make_page_readonly(void *va)
queue_l1_entry_update(pte, (*(unsigned long *)pte)&~_PAGE_RW);
}
static inline void __make_page_writeable(void *va)
static inline void __make_page_writable(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
@@ -321,14 +321,14 @@ static inline void make_page_readonly(void *va)
*(unsigned long *)pte&PAGE_MASK));
}
static inline void make_page_writeable(void *va)
static inline void make_page_writable(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
pte_t *pte = pte_offset(pmd, (unsigned long)va);
queue_l1_entry_update(pte, (*(unsigned long *)pte)|_PAGE_RW);
if ( (unsigned long)va >= VMALLOC_START )
__make_page_writeable(machine_to_virt(
__make_page_writable(machine_to_virt(
*(unsigned long *)pte&PAGE_MASK));
}
@@ -341,11 +341,11 @@ static inline void make_pages_readonly(void *va, unsigned int nr)
}
}
static inline void make_pages_writeable(void *va, unsigned int nr)
static inline void make_pages_writable(void *va, unsigned int nr)
{
while ( nr-- != 0 )
{
make_page_writeable(va);
make_page_writable(va);
va = (void *)((unsigned long)va + PAGE_SIZE);
}
}
@@ -71,7 +71,7 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
#endif
}
if (oldsize) {
make_pages_writeable(oldldt, (oldsize * LDT_ENTRY_SIZE) /
make_pages_writable(oldldt, (oldsize * LDT_ENTRY_SIZE) /
PAGE_SIZE);
flush_page_update_queue();
if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
@@ -121,9 +121,9 @@ void destroy_context(struct mm_struct *mm)
if (mm->context.size) {
if (mm == current->active_mm)
clear_LDT();
make_pages_writeable(mm->context.ldt,
(mm->context.size * LDT_ENTRY_SIZE) /
PAGE_SIZE);
make_pages_writable(mm->context.ldt,
(mm->context.size * LDT_ENTRY_SIZE) /
PAGE_SIZE);
flush_page_update_queue();
if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
vfree(mm->context.ldt);
@@ -1106,7 +1106,7 @@ void __init setup_arch(char **cmdline_p)
VMASST_TYPE_4gb_segments);
#ifdef CONFIG_XEN_WRITABLE_PAGETABLES
HYPERVISOR_vm_assist(VMASST_CMD_enable,
VMASST_TYPE_writeable_pagetables);
VMASST_TYPE_writable_pagetables);
#endif
pm_idle = xen_cpu_idle;
@@ -995,7 +995,7 @@ void __init trap_init(void)
* ensures this end result (blow away the selector value) without the dangers
* of the normal page-fault handler.
*
* NB. Perhaps this can all go away after we have implemented writeable
* NB. Perhaps this can all go away after we have implemented writable
* page tables. :-)
*/
@@ -280,7 +280,7 @@ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
unsigned long flags; /* can be called from interrupt context */
queue_pgd_unpin(__pa(pgd));
__make_page_writeable(pgd);
__make_page_writable(pgd);
flush_page_update_queue();
if (PTRS_PER_PMD > 1)
@@ -98,7 +98,7 @@ static void __do_suspend(void)
VMASST_TYPE_4gb_segments);
#ifdef CONFIG_XEN_WRITABLE_PAGETABLES
HYPERVISOR_vm_assist(VMASST_CMD_enable,
VMASST_TYPE_writeable_pagetables);
VMASST_TYPE_writable_pagetables);
#endif
shutting_down = -1;
@@ -32,7 +32,7 @@ extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
static inline void pte_free_kernel(pte_t *pte)
{
free_page((unsigned long)pte);
__make_page_writeable(pte);
__make_page_writable(pte);
}
static inline void pte_free(struct page *pte)
@@ -41,7 +41,7 @@ static inline void pte_free(struct page *pte)
if (pte < highmem_start_page)
#endif
{
__make_page_writeable(phys_to_virt(page_to_pseudophys(pte)));
__make_page_writable(phys_to_virt(page_to_pseudophys(pte)));
__free_page(pte);
}
}
@@ -281,7 +281,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define pmd_clear(xp) do { \
pmd_t p = *(xp); \
set_pmd(xp, __pmd(0)); \
__make_page_writeable((void *)pmd_page_kernel(p)); \
__make_page_writable((void *)pmd_page_kernel(p)); \
/* XXXcl queue */ \
} while (0)
@@ -401,7 +401,7 @@ static inline void __make_page_readonly(void *va)
queue_l1_entry_update(pte, (*(unsigned long *)pte)&~_PAGE_RW);
}
static inline void __make_page_writeable(void *va)
static inline void __make_page_writable(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
@@ -421,14 +421,14 @@ static inline void make_page_readonly(void *va)
/* XXXcl queue */
}
static inline void make_page_writeable(void *va)
static inline void make_page_writable(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
pte_t *pte = pte_offset_kernel(pmd, (unsigned long)va);
queue_l1_entry_update(pte, (*(unsigned long *)pte)|_PAGE_RW);
if ( (unsigned long)va >= VMALLOC_START )
__make_page_writeable(machine_to_virt(
__make_page_writable(machine_to_virt(
*(unsigned long *)pte&PAGE_MASK));
/* XXXcl queue */
}
@@ -443,11 +443,11 @@ static inline void make_pages_readonly(void *va, unsigned int nr)
/* XXXcl queue */
}
static inline void make_pages_writeable(void *va, unsigned int nr)
static inline void make_pages_writable(void *va, unsigned int nr)
{
while ( nr-- != 0 )
{
make_page_writeable(va);
make_page_writable(va);
va = (void *)((unsigned long)va + PAGE_SIZE);
}
/* XXXcl queue */
+1 -1
View File
@@ -716,7 +716,7 @@ int construct_dom0(struct domain *p,
page = &frame_table[mfn];
set_bit(_PGC_tlb_flush_on_type_change, &page->u.inuse.count_info);
if ( !get_page_and_type(page, p, PGT_writeable_page) )
if ( !get_page_and_type(page, p, PGT_writable_page) )
BUG();
mfn++;
-1
View File
@@ -7,7 +7,6 @@
processor: 0, \
domain: IDLE_DOMAIN_ID, \
mm: IDLE0_MM, \
addr_limit: KERNEL_DS, \
thread: INIT_THREAD, \
flags: 1<<DF_IDLETASK, \
refcnt: ATOMIC_INIT(1) \
+45 -36
View File
@@ -38,7 +38,7 @@
*
* TYPE_COUNT is more subtle. A frame can be put to one of three
* mutually-exclusive uses: it might be used as a page directory, or a
* page table, or it may be mapped writeable by the domain [of course, a
* page table, or it may be mapped writable by the domain [of course, a
* frame may not be used in any of these three ways!].
* So, type_count is a count of the number of times a frame is being
* referred to in its current incarnation. Therefore, a page can only
@@ -53,10 +53,10 @@
* point safety checks would need to be carried out next time the count
* is increased again.
*
* A further note on writeable page mappings:
* ------------------------------------------
* For simplicity, the count of writeable mappings for a page may not
* correspond to reality. The 'writeable count' is incremented for every
* A further note on writable page mappings:
* -----------------------------------------
* For simplicity, the count of writable mappings for a page may not
* correspond to reality. The 'writable count' is incremented for every
* PTE which maps the page with the _PAGE_RW flag set. However, for
* write access to be possible the page directory entry must also have
* its _PAGE_RW bit set. We do not check this as it complicates the
@@ -70,12 +70,12 @@
* -----------------------------------------
* We want domains to be able to map pages for read-only access. The
* main reason is that page tables and directories should be readable
* by a domain, but it would not be safe for them to be writeable.
* by a domain, but it would not be safe for them to be writable.
* However, domains have free access to rings 1 & 2 of the Intel
* privilege model. In terms of page protection, these are considered
* to be part of 'supervisor mode'. The WP bit in CR0 controls whether
* read-only restrictions are respected in supervisor mode -- if the
* bit is clear then any mapped page is writeable.
* bit is clear then any mapped page is writable.
*
* We get round this by always setting the WP bit and disallowing
* updates to it. This is very unlikely to cause a problem for guest
@@ -143,12 +143,15 @@ static struct domain *dom_xen, *dom_io;
void arch_init_memory(void)
{
static void ptwr_init_backpointers(void);
static void ptwr_disable(void);
unsigned long mfn;
memset(percpu_info, 0, sizeof(percpu_info));
vm_assist_info[VMASST_TYPE_writeable_pagetables].enable =
vm_assist_info[VMASST_TYPE_writable_pagetables].enable =
ptwr_init_backpointers;
vm_assist_info[VMASST_TYPE_writable_pagetables].disable =
ptwr_disable;
/* Initialise to a magic of 0x55555555 so easier to spot bugs later. */
memset(machine_to_phys_mapping, 0x55, 4<<20);
@@ -397,7 +400,7 @@ get_page_from_l1e(
if ( l1v & _PAGE_RW )
{
if ( unlikely(!get_page_and_type_from_pagenr(
pfn, PGT_writeable_page, d)) )
pfn, PGT_writable_page, d)) )
return 0;
set_bit(_PGC_tlb_flush_on_type_change,
&frame_table[pfn].u.inuse.count_info);
@@ -1020,17 +1023,21 @@ int do_mmu_update(mmu_update_t *ureqs, int count, int *success_count)
unsigned int cmd;
unsigned long prev_spfn = 0;
l1_pgentry_t *prev_spl1e = 0;
struct domain *d = current;
perfc_incrc(calls_to_mmu_update);
perfc_addc(num_page_updates, count);
cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
cleanup_writable_pagetable(d, PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
if ( unlikely(!access_ok(VERIFY_READ, ureqs, count * sizeof(req))) )
return -EFAULT;
for ( i = 0; i < count; i++ )
{
if ( unlikely(copy_from_user(&req, ureqs, sizeof(req)) != 0) )
if ( unlikely(__copy_from_user(&req, ureqs, sizeof(req)) != 0) )
{
MEM_LOG("Bad copy_from_user");
MEM_LOG("Bad __copy_from_user");
rc = -EFAULT;
break;
}
@@ -1073,13 +1080,13 @@ int do_mmu_update(mmu_update_t *ureqs, int count, int *success_count)
okay = mod_l1_entry((l1_pgentry_t *)va,
mk_l1_pgentry(req.val));
if ( okay && unlikely(current->mm.shadow_mode) &&
(get_shadow_status(&current->mm, page-frame_table) &
if ( unlikely(d->mm.shadow_mode) && okay &&
(get_shadow_status(&d->mm, page-frame_table) &
PSH_shadowed) )
{
shadow_l1_normal_pt_update( req.ptr, req.val,
&prev_spfn, &prev_spl1e );
put_shadow_status(&current->mm);
shadow_l1_normal_pt_update(
req.ptr, req.val, &prev_spfn, &prev_spl1e);
put_shadow_status(&d->mm);
}
put_page_type(page);
@@ -1092,19 +1099,19 @@ int do_mmu_update(mmu_update_t *ureqs, int count, int *success_count)
mk_l2_pgentry(req.val),
pfn);
if ( okay && unlikely(current->mm.shadow_mode) &&
(get_shadow_status(&current->mm, page-frame_table) &
if ( unlikely(d->mm.shadow_mode) && okay &&
(get_shadow_status(&d->mm, page-frame_table) &
PSH_shadowed) )
{
shadow_l2_normal_pt_update( req.ptr, req.val );
put_shadow_status(&current->mm);
shadow_l2_normal_pt_update(req.ptr, req.val);
put_shadow_status(&d->mm);
}
put_page_type(page);
}
break;
default:
if ( likely(get_page_type(page, PGT_writeable_page)) )
if ( likely(get_page_type(page, PGT_writable_page)) )
{
*(unsigned long *)va = req.val;
okay = 1;
@@ -1114,7 +1121,6 @@ int do_mmu_update(mmu_update_t *ureqs, int count, int *success_count)
}
put_page(page);
break;
case MMU_MACHPHYS_UPDATE:
@@ -1131,8 +1137,8 @@ int do_mmu_update(mmu_update_t *ureqs, int count, int *success_count)
* If in log-dirty mode, mark the corresponding pseudo-physical
* page as dirty.
*/
if ( unlikely(current->mm.shadow_mode == SHM_logdirty) )
mark_dirty(&current->mm, pfn);
if ( unlikely(d->mm.shadow_mode == SHM_logdirty) )
mark_dirty(&d->mm, pfn);
put_page(&frame_table[pfn]);
break;
@@ -1163,7 +1169,7 @@ int do_mmu_update(mmu_update_t *ureqs, int count, int *success_count)
if ( prev_pfn != 0 )
unmap_domain_mem((void *)va);
if( prev_spl1e != 0 )
if ( unlikely(prev_spl1e != 0) )
unmap_domain_mem((void *)prev_spl1e);
deferred_ops = percpu_info[cpu].deferred_ops;
@@ -1171,7 +1177,7 @@ int do_mmu_update(mmu_update_t *ureqs, int count, int *success_count)
if ( deferred_ops & DOP_FLUSH_TLB )
local_flush_tlb();
if ( deferred_ops & DOP_RELOAD_LDT )
(void)map_ldt_shadow_page(0);
@@ -1192,9 +1198,9 @@ int do_update_va_mapping(unsigned long page_nr,
unsigned long val,
unsigned long flags)
{
struct domain *p = current;
struct domain *d = current;
int err = 0;
unsigned int cpu = p->processor;
unsigned int cpu = d->processor;
unsigned long deferred_ops;
perfc_incrc(calls_to_update_va);
@@ -1202,7 +1208,7 @@ int do_update_va_mapping(unsigned long page_nr,
if ( unlikely(page_nr >= (HYPERVISOR_VIRT_START >> PAGE_SHIFT)) )
return -EINVAL;
cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
cleanup_writable_pagetable(d, PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
/*
* XXX When we make this support 4MB superpages we should also deal with
@@ -1213,11 +1219,11 @@ int do_update_va_mapping(unsigned long page_nr,
mk_l1_pgentry(val))) )
err = -EINVAL;
if ( unlikely(p->mm.shadow_mode) )
if ( unlikely(d->mm.shadow_mode) )
{
unsigned long sval;
l1pte_no_fault( &current->mm, &val, &sval );
l1pte_no_fault(&d->mm, &val, &sval);
if ( unlikely(__put_user(sval, ((unsigned long *)(
&shadow_linear_pg_table[page_nr])))) )
@@ -1234,10 +1240,10 @@ int do_update_va_mapping(unsigned long page_nr,
* the PTE in the PT-holding page. We need the machine frame number
* for this.
*/
if ( p->mm.shadow_mode == SHM_logdirty )
if ( d->mm.shadow_mode == SHM_logdirty )
mark_dirty( &current->mm, va_to_l1mfn(page_nr<<PAGE_SHIFT) );
check_pagetable( p, p->mm.pagetable, "va" ); /* debug */
check_pagetable(d, d->mm.pagetable, "va"); /* debug */
}
deferred_ops = percpu_info[cpu].deferred_ops;
@@ -1267,8 +1273,6 @@ int do_update_va_mapping_otherdomain(unsigned long page_nr,
if ( unlikely(!IS_PRIV(current)) )
return -EPERM;
cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
percpu_info[cpu].foreign = d = find_domain_by_id(domid);
if ( unlikely(d == NULL) )
{
@@ -1576,6 +1580,11 @@ static void ptwr_init_backpointers(void)
}
}
static void ptwr_disable(void)
{
__cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
}
#ifndef NDEBUG
void ptwr_status(void)
{
+11 -9
View File
@@ -328,17 +328,19 @@ asmlinkage void do_page_fault(struct pt_regs *regs, long error_code)
return; /* successfully copied the mapping */
}
if ( (addr >> L2_PAGETABLE_SHIFT) == ptwr_info[cpu].disconnected )
if ( unlikely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
{
ptwr_reconnect_disconnected(addr);
return;
}
if ( (addr >> L2_PAGETABLE_SHIFT) == ptwr_info[cpu].disconnected )
{
ptwr_reconnect_disconnected(addr);
return;
}
if ( VM_ASSIST(d, VMASST_TYPE_writeable_pagetables) &&
(addr < PAGE_OFFSET) &&
((error_code & 3) == 3) && /* write-protection fault */
ptwr_do_page_fault(addr) )
return;
if ( (addr < PAGE_OFFSET) &&
((error_code & 3) == 3) && /* write-protection fault */
ptwr_do_page_fault(addr) )
return;
}
if ( unlikely(d->mm.shadow_mode) &&
(addr < PAGE_OFFSET) && shadow_fault(addr, error_code) )
+2 -1
View File
@@ -718,8 +718,9 @@ ENTRY(hypercall_table)
.long SYMBOL_NAME(do_xen_version)
.long SYMBOL_NAME(do_console_io)
.long SYMBOL_NAME(do_physdev_op)
.long SYMBOL_NAME(do_update_va_mapping_otherdomain) /* 20 */
.long SYMBOL_NAME(do_grant_table_op) /* 20 */
.long SYMBOL_NAME(do_vm_assist)
.long SYMBOL_NAME(do_update_va_mapping_otherdomain)
.rept NR_hypercalls-((.-hypercall_table)/4)
.long SYMBOL_NAME(do_ni_hypercall)
.endr
+1 -1
View File
@@ -357,7 +357,7 @@ long do_update_descriptor(
goto out;
break;
default:
if ( unlikely(!get_page_type(page, PGT_writeable_page)) )
if ( unlikely(!get_page_type(page, PGT_writable_page)) )
goto out;
break;
}
+449 -60
View File
@@ -6,62 +6,21 @@
* Copyright 1997 Linus Torvalds
*/
#include <xen/config.h>
#include <xen/mm.h>
#include <asm/uaccess.h>
//#include <asm/mmx.h>
#ifdef CONFIG_X86_USE_3DNOW_AND_WORKS
#define might_sleep() ((void)0)
unsigned long
__generic_copy_to_user(void *to, const void *from, unsigned long n)
static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
{
if (access_ok(VERIFY_WRITE, to, n))
{
if(n<512)
__copy_user(to,from,n);
else
mmx_copy_user(to,from,n);
}
return n;
}
unsigned long
__generic_copy_from_user(void *to, const void *from, unsigned long n)
{
if (access_ok(VERIFY_READ, from, n))
{
if(n<512)
__copy_user_zeroing(to,from,n);
else
mmx_copy_user_zeroing(to, from, n);
}
else
memset(to, 0, n);
return n;
}
#else
unsigned long
__generic_copy_to_user(void *to, const void *from, unsigned long n)
{
prefetch(from);
if (access_ok(VERIFY_WRITE, to, n))
__copy_user(to,from,n);
return n;
}
unsigned long
__generic_copy_from_user(void *to, const void *from, unsigned long n)
{
prefetchw(to);
if (access_ok(VERIFY_READ, from, n))
__copy_user_zeroing(to,from,n);
else
memset(to, 0, n);
return n;
}
#ifdef CONFIG_X86_INTEL_USERCOPY
if (n >= 64 && ((a1 ^ a2) & movsl_mask.mask))
return 0;
#endif
return 1;
}
#define movsl_is_ok(a1,a2,n) \
__movsl_is_ok((unsigned long)(a1),(unsigned long)(a2),(n))
/*
* Copy a null terminated string from userspace.
@@ -95,16 +54,54 @@ do { \
: "memory"); \
} while (0)
/**
* __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
* @dst: Destination address, in kernel space. This buffer must be at
* least @count bytes long.
* @src: Source address, in user space.
* @count: Maximum number of bytes to copy, including the trailing NUL.
*
* Copies a NUL-terminated string from userspace to kernel space.
* Caller must check the specified block with access_ok() before calling
* this function.
*
* On success, returns the length of the string (not including the trailing
* NUL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
long
__strncpy_from_user(char *dst, const char *src, long count)
__strncpy_from_user(char *dst, const char __user *src, long count)
{
long res;
__do_strncpy_from_user(dst, src, count, res);
return res;
}
/**
* strncpy_from_user: - Copy a NUL terminated string from userspace.
* @dst: Destination address, in kernel space. This buffer must be at
* least @count bytes long.
* @src: Source address, in user space.
* @count: Maximum number of bytes to copy, including the trailing NUL.
*
* Copies a NUL-terminated string from userspace to kernel space.
*
* On success, returns the length of the string (not including the trailing
* NUL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
long
strncpy_from_user(char *dst, const char *src, long count)
strncpy_from_user(char *dst, const char __user *src, long count)
{
long res = -EFAULT;
if (access_ok(VERIFY_READ, src, 1))
@@ -138,32 +135,61 @@ do { \
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
} while (0)
/**
* clear_user: - Zero a block of memory in user space.
* @to: Destination address, in user space.
* @n: Number of bytes to zero.
*
* Zero a block of memory in user space.
*
* Returns number of bytes that could not be cleared.
* On success, this will be zero.
*/
unsigned long
clear_user(void *to, unsigned long n)
clear_user(void __user *to, unsigned long n)
{
might_sleep();
if (access_ok(VERIFY_WRITE, to, n))
__do_clear_user(to, n);
return n;
}
/**
* __clear_user: - Zero a block of memory in user space, with less checking.
* @to: Destination address, in user space.
* @n: Number of bytes to zero.
*
* Zero a block of memory in user space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be cleared.
* On success, this will be zero.
*/
unsigned long
__clear_user(void *to, unsigned long n)
__clear_user(void __user *to, unsigned long n)
{
__do_clear_user(to, n);
return n;
}
/*
* Return the size of a string (including the ending 0)
/**
* strlen_user: - Get the size of a string in user space.
* @s: The string to measure.
* @n: The maximum valid length
*
* Return 0 on exception, a value greater than N if too long
* Get the size of a NUL-terminated string in user space.
*
* Returns the size of the string INCLUDING the terminating NUL.
* On exception, returns 0.
* If the string is too long, returns a value greater than @n.
*/
long strnlen_user(const char *s, long n)
long strnlen_user(const char __user *s, long n)
{
unsigned long mask = -__addr_ok(s);
unsigned long res, tmp;
might_sleep();
__asm__ __volatile__(
" testl %0, %0\n"
" jz 3f\n"
@@ -188,3 +214,366 @@ long strnlen_user(const char *s, long n)
:"cc");
return res & mask;
}
#ifdef CONFIG_X86_INTEL_USERCOPY
static unsigned long
__copy_user_intel(void __user *to, const void *from, unsigned long size)
{
int d0, d1;
__asm__ __volatile__(
" .align 2,0x90\n"
"1: movl 32(%4), %%eax\n"
" cmpl $67, %0\n"
" jbe 3f\n"
"2: movl 64(%4), %%eax\n"
" .align 2,0x90\n"
"3: movl 0(%4), %%eax\n"
"4: movl 4(%4), %%edx\n"
"5: movl %%eax, 0(%3)\n"
"6: movl %%edx, 4(%3)\n"
"7: movl 8(%4), %%eax\n"
"8: movl 12(%4),%%edx\n"
"9: movl %%eax, 8(%3)\n"
"10: movl %%edx, 12(%3)\n"
"11: movl 16(%4), %%eax\n"
"12: movl 20(%4), %%edx\n"
"13: movl %%eax, 16(%3)\n"
"14: movl %%edx, 20(%3)\n"
"15: movl 24(%4), %%eax\n"
"16: movl 28(%4), %%edx\n"
"17: movl %%eax, 24(%3)\n"
"18: movl %%edx, 28(%3)\n"
"19: movl 32(%4), %%eax\n"
"20: movl 36(%4), %%edx\n"
"21: movl %%eax, 32(%3)\n"
"22: movl %%edx, 36(%3)\n"
"23: movl 40(%4), %%eax\n"
"24: movl 44(%4), %%edx\n"
"25: movl %%eax, 40(%3)\n"
"26: movl %%edx, 44(%3)\n"
"27: movl 48(%4), %%eax\n"
"28: movl 52(%4), %%edx\n"
"29: movl %%eax, 48(%3)\n"
"30: movl %%edx, 52(%3)\n"
"31: movl 56(%4), %%eax\n"
"32: movl 60(%4), %%edx\n"
"33: movl %%eax, 56(%3)\n"
"34: movl %%edx, 60(%3)\n"
" addl $-64, %0\n"
" addl $64, %4\n"
" addl $64, %3\n"
" cmpl $63, %0\n"
" ja 1b\n"
"35: movl %0, %%eax\n"
" shrl $2, %0\n"
" andl $3, %%eax\n"
" cld\n"
"99: rep; movsl\n"
"36: movl %%eax, %0\n"
"37: rep; movsb\n"
"100:\n"
".section .fixup,\"ax\"\n"
"101: lea 0(%%eax,%0,4),%0\n"
" jmp 100b\n"
".previous\n"
".section __ex_table,\"a\"\n"
" .align 4\n"
" .long 1b,100b\n"
" .long 2b,100b\n"
" .long 3b,100b\n"
" .long 4b,100b\n"
" .long 5b,100b\n"
" .long 6b,100b\n"
" .long 7b,100b\n"
" .long 8b,100b\n"
" .long 9b,100b\n"
" .long 10b,100b\n"
" .long 11b,100b\n"
" .long 12b,100b\n"
" .long 13b,100b\n"
" .long 14b,100b\n"
" .long 15b,100b\n"
" .long 16b,100b\n"
" .long 17b,100b\n"
" .long 18b,100b\n"
" .long 19b,100b\n"
" .long 20b,100b\n"
" .long 21b,100b\n"
" .long 22b,100b\n"
" .long 23b,100b\n"
" .long 24b,100b\n"
" .long 25b,100b\n"
" .long 26b,100b\n"
" .long 27b,100b\n"
" .long 28b,100b\n"
" .long 29b,100b\n"
" .long 30b,100b\n"
" .long 31b,100b\n"
" .long 32b,100b\n"
" .long 33b,100b\n"
" .long 34b,100b\n"
" .long 35b,100b\n"
" .long 36b,100b\n"
" .long 37b,100b\n"
" .long 99b,101b\n"
".previous"
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
return size;
}
static unsigned long
__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size)
{
int d0, d1;
__asm__ __volatile__(
" .align 2,0x90\n"
"0: movl 32(%4), %%eax\n"
" cmpl $67, %0\n"
" jbe 2f\n"
"1: movl 64(%4), %%eax\n"
" .align 2,0x90\n"
"2: movl 0(%4), %%eax\n"
"21: movl 4(%4), %%edx\n"
" movl %%eax, 0(%3)\n"
" movl %%edx, 4(%3)\n"
"3: movl 8(%4), %%eax\n"
"31: movl 12(%4),%%edx\n"
" movl %%eax, 8(%3)\n"
" movl %%edx, 12(%3)\n"
"4: movl 16(%4), %%eax\n"
"41: movl 20(%4), %%edx\n"
" movl %%eax, 16(%3)\n"
" movl %%edx, 20(%3)\n"
"10: movl 24(%4), %%eax\n"
"51: movl 28(%4), %%edx\n"
" movl %%eax, 24(%3)\n"
" movl %%edx, 28(%3)\n"
"11: movl 32(%4), %%eax\n"
"61: movl 36(%4), %%edx\n"
" movl %%eax, 32(%3)\n"
" movl %%edx, 36(%3)\n"
"12: movl 40(%4), %%eax\n"
"71: movl 44(%4), %%edx\n"
" movl %%eax, 40(%3)\n"
" movl %%edx, 44(%3)\n"
"13: movl 48(%4), %%eax\n"
"81: movl 52(%4), %%edx\n"
" movl %%eax, 48(%3)\n"
" movl %%edx, 52(%3)\n"
"14: movl 56(%4), %%eax\n"
"91: movl 60(%4), %%edx\n"
" movl %%eax, 56(%3)\n"
" movl %%edx, 60(%3)\n"
" addl $-64, %0\n"
" addl $64, %4\n"
" addl $64, %3\n"
" cmpl $63, %0\n"
" ja 0b\n"
"5: movl %0, %%eax\n"
" shrl $2, %0\n"
" andl $3, %%eax\n"
" cld\n"
"6: rep; movsl\n"
" movl %%eax,%0\n"
"7: rep; movsb\n"
"8:\n"
".section .fixup,\"ax\"\n"
"9: lea 0(%%eax,%0,4),%0\n"
"16: pushl %0\n"
" pushl %%eax\n"
" xorl %%eax,%%eax\n"
" rep; stosb\n"
" popl %%eax\n"
" popl %0\n"
" jmp 8b\n"
".previous\n"
".section __ex_table,\"a\"\n"
" .align 4\n"
" .long 0b,16b\n"
" .long 1b,16b\n"
" .long 2b,16b\n"
" .long 21b,16b\n"
" .long 3b,16b\n"
" .long 31b,16b\n"
" .long 4b,16b\n"
" .long 41b,16b\n"
" .long 10b,16b\n"
" .long 51b,16b\n"
" .long 11b,16b\n"
" .long 61b,16b\n"
" .long 12b,16b\n"
" .long 71b,16b\n"
" .long 13b,16b\n"
" .long 81b,16b\n"
" .long 14b,16b\n"
" .long 91b,16b\n"
" .long 6b,9b\n"
" .long 7b,16b\n"
".previous"
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
return size;
}
#else
/*
* Leave these declared but undefined. They should not be any references to
* them
*/
unsigned long
__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size);
unsigned long
__copy_user_intel(void __user *to, const void *from, unsigned long size);
#endif /* CONFIG_X86_INTEL_USERCOPY */
/* Generic arbitrary sized copy. */
#define __copy_user(to,from,size) \
do { \
int __d0, __d1, __d2; \
__asm__ __volatile__( \
" cmp $7,%0\n" \
" jbe 1f\n" \
" movl %1,%0\n" \
" negl %0\n" \
" andl $7,%0\n" \
" subl %0,%3\n" \
"4: rep; movsb\n" \
" movl %3,%0\n" \
" shrl $2,%0\n" \
" andl $3,%3\n" \
" .align 2,0x90\n" \
"0: rep; movsl\n" \
" movl %3,%0\n" \
"1: rep; movsb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"5: addl %3,%0\n" \
" jmp 2b\n" \
"3: lea 0(%3,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 4b,5b\n" \
" .long 0b,3b\n" \
" .long 1b,2b\n" \
".previous" \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \
} while (0)
#define __copy_user_zeroing(to,from,size) \
do { \
int __d0, __d1, __d2; \
__asm__ __volatile__( \
" cmp $7,%0\n" \
" jbe 1f\n" \
" movl %1,%0\n" \
" negl %0\n" \
" andl $7,%0\n" \
" subl %0,%3\n" \
"4: rep; movsb\n" \
" movl %3,%0\n" \
" shrl $2,%0\n" \
" andl $3,%3\n" \
" .align 2,0x90\n" \
"0: rep; movsl\n" \
" movl %3,%0\n" \
"1: rep; movsb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"5: addl %3,%0\n" \
" jmp 6f\n" \
"3: lea 0(%3,%0,4),%0\n" \
"6: pushl %0\n" \
" pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" rep; stosb\n" \
" popl %%eax\n" \
" popl %0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 4b,5b\n" \
" .long 0b,3b\n" \
" .long 1b,6b\n" \
".previous" \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \
} while (0)
unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n)
{
if (movsl_is_ok(to, from, n))
__copy_user(to, from, n);
else
n = __copy_user_intel(to, from, n);
return n;
}
unsigned long
__copy_from_user_ll(void *to, const void __user *from, unsigned long n)
{
if (movsl_is_ok(to, from, n))
__copy_user_zeroing(to, from, n);
else
n = __copy_user_zeroing_intel(to, from, n);
return n;
}
/**
* copy_to_user: - Copy a block of data into user space.
* @to: Destination address, in user space.
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from kernel space to user space.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*/
unsigned long
copy_to_user(void __user *to, const void *from, unsigned long n)
{
might_sleep();
if (access_ok(VERIFY_WRITE, to, n))
n = __copy_to_user(to, from, n);
return n;
}
EXPORT_SYMBOL(copy_to_user);
/**
* copy_from_user: - Copy a block of data from user space.
* @to: Destination address, in kernel space.
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from user space to kernel space.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*
* If some data could not be copied, this function will pad the copied
* data to the requested size using zero bytes.
*/
unsigned long
copy_from_user(void *to, const void __user *from, unsigned long n)
{
might_sleep();
if (access_ok(VERIFY_READ, from, n))
n = __copy_from_user(to, from, n);
else
memset(to, 0, n);
return n;
}
EXPORT_SYMBOL(copy_from_user);
+10 -2
View File
@@ -23,6 +23,10 @@ static long alloc_dom_mem(struct domain *d,
struct pfn_info *page;
unsigned long i;
if ( unlikely(!access_ok(VERIFY_WRITE, extent_list,
nr_extents*sizeof(*extent_list))) )
return 0;
if ( (extent_order != 0) && !IS_CAPABLE_PHYSDEV(current) )
{
DPRINTK("Only I/O-capable domains may allocate > order-0 memory.\n");
@@ -38,7 +42,7 @@ static long alloc_dom_mem(struct domain *d,
}
/* Inform the domain of the new page's machine address. */
if ( unlikely(put_user(page_to_pfn(page), &extent_list[i]) != 0) )
if ( unlikely(__put_user(page_to_pfn(page), &extent_list[i]) != 0) )
return i;
}
@@ -53,9 +57,13 @@ static long free_dom_mem(struct domain *d,
struct pfn_info *page;
unsigned long i, j, mpfn;
if ( unlikely(!access_ok(VERIFY_READ, extent_list,
nr_extents*sizeof(*extent_list))) )
return 0;
for ( i = 0; i < nr_extents; i++ )
{
if ( unlikely(get_user(mpfn, &extent_list[i]) != 0) )
if ( unlikely(__get_user(mpfn, &extent_list[i]) != 0) )
return i;
for ( j = 0; j < (1 << extent_order); j++ )
-2
View File
@@ -65,8 +65,6 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
strncpy(d->name, buf, MAX_DOMAIN_NAME);
d->name[MAX_DOMAIN_NAME-1] = '\0';
d->addr_limit = USER_DS;
arch_do_createdomain(d);
sched_add_domain(d);
+130 -47
View File
@@ -21,58 +21,141 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define __GRANT_TABLE_IMPLEMENTATION__
typedef struct grant_table grant_table_t;
#include <xen/config.h>
#include <xen/sched.h>
#include <hypervisor-ifs/grant_table.h>
/* Active grant entry - used for shadowing GTF_permit_access grants. */
typedef struct {
u32 counts; /* Reference count information. */
u16 next; /* Mapping hash chain. */
domid_t domid; /* Domain being granted access. */
unsigned long frame; /* Frame being granted. */
} active_grant_entry_t;
#define update_shared_flags(x,y,z) (0)
/* Bitfields in active_grant_entry_t:counts. */
/* Grant is pinned by 'domid' for read mappings and I/O. */
#define _GNTCNT_read_pinned (0)
#define GNTCNT_read_pinned (1<<_GNTCNT_read_pinned)
/* Grant is pinned by 'domid' for write mappings and I/O. */
#define _GNTCNT_write_pinned (1)
#define GNTCNT_write_pinned (1<<_GNTCNT_write_pinned)
/* Grant is pinned in IOMMU (read-only unless GNTCNT_write_pinned). */
#define _GNTCNT_io_pinned (2)
#define GNTCNT_io_pinned (1<<_GNTCNT_io_pinned)
/* Grant is mappable (read-only unless GNTCNT_write_pinned). */
#define _GNTCNT_mappable (3)
#define GNTCNT_mappable (1<<_GNTCNT_mappable)
/* Count of writable page mappings. (!GNTCNT_write_pinned => count==0). */
#define GNTCNT_wmap_shift (4)
#define GNTCNT_wmap_mask (0x3FFFU << GNTCNT_wmap_shift)
/* Count of read-only page mappings. */
#define GNTCNT_rmap_shift (18)
#define GNTCNT_rmap_mask (0x3FFFU << GNTCNT_rmap_shift)
static long gnttab_update_pin_status(gnttab_update_pin_status_t *uop)
{
domid_t dom, sdom;
grant_ref_t ref;
u16 pin_flags;
struct domain *ld, *rd;
u32 sflags;
active_grant_entry_t *act;
grant_entry_t *sha;
long rc = 0;
#define MAPHASH_SZ (256)
#define MAPHASH(_k) ((_k) & (MAPHASH_SZ-1))
#define MAPHASH_INVALID (0xFFFFU)
ld = current;
#define NR_GRANT_ENTRIES (PAGE_SIZE / sizeof(grant_entry_t))
if ( unlikely(__get_user(dom, &uop->dom)) ||
unlikely(__get_user(ref, &uop->ref)) ||
unlikely(__get_user(pin_flags, &uop->pin_flags)) )
return -EFAULT;
/* Per-domain grant information. */
struct grant_table {
/* 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. */
spinlock_t lock;
/* Hash table: frame -> active grant entry. */
u16 maphash[MAPHASH_SZ];
};
pin_flags &= (GNTPIN_dev_accessible |
GNTPIN_host_accessible |
GNTPIN_readonly);
if ( unlikely(ref >= NR_GRANT_ENTRIES) ||
unlikely(pin_flags == GNTPIN_readonly) )
return -EINVAL;
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) )
return -ESRCH;
act = &rd->grant_table->active[ref];
sha = &rd->grant_table->shared[ref];
if ( act->status == 0 )
{
if ( unlikely(pin_flags == 0) )
goto out;
sflags = sha->flags;
sdom = sha->domid;
do {
if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) ||
unlikely(sdom != ld->domain) )
{
}
sflags |= GTF_reading;
if ( !(pin_flags & GNTPIN_readonly) )
{
sflags |= GTF_writing;
if ( unlikely(sflags & GTF_readonly) )
{
}
}
}
while ( !update_shared_flags(sha, sflags, sdom) );
act->status = pin_flags;
act->domid = sdom;
/* XXX MAP XXX */
}
else if ( pin_flags == 0 )
{
if ( unlikely((act->status &
(GNTPIN_wmap_mask|GNTPIN_rmap_mask)) != 0) )
{
}
clear_bit(_GTF_writing, &sha->flags);
clear_bit(_GTF_reading, &sha->flags);
act->status = 0;
/* XXX UNMAP XXX */
}
else
{
if ( pin_flags & GNTPIN_readonly )
{
if ( !(act->status & GNTPIN_readonly) )
{
}
}
else if ( act->status & GNTPIN_readonly )
{
}
if ( pin_flags & GNTPIN_host_accessible )
{
if ( !(act->status & GNTPIN_host_accessible) )
{
/* XXX MAP XXX */
}
}
else if ( act->status & GNTPIN_host_accessible )
{
/* XXX UNMAP XXX */
}
act->status &= ~GNTPIN_dev_accessible;
act->status |= pin_flags & GNTPIN_dev_accessible;
}
out:
put_domain(rd);
return rc;
}
long do_grant_table_op(gnttab_op_t *uop)
{
long rc;
u32 cmd;
if ( unlikely(!access_ok(VERIFY_WRITE, uop, sizeof(*uop))) ||
unlikely(__get_user(cmd, &uop->cmd)) )
return -EFAULT;
switch ( cmd )
{
case GNTTABOP_update_pin_status:
rc = gnttab_update_pin_status(&uop->u.update_pin_status);
break;
default:
rc = -ENOSYS;
break;
}
return rc;
}
int grant_table_create(struct domain *d)
{
@@ -86,8 +169,8 @@ int grant_table_create(struct domain *d)
t->shared = NULL;
t->active = NULL;
spin_lock_init(&t->lock);
for ( i = 0; i < MAPHASH_SZ; i++ )
t->maphash[i] = MAPHASH_INVALID;
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) *
+2 -1
View File
@@ -371,7 +371,8 @@ void __enter_scheduler(void)
if ( unlikely(prev == next) )
return;
cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
cleanup_writable_pagetable(
prev, PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
#ifdef PTWR_TRACK_DOMAIN
{
+12 -6
View File
@@ -67,7 +67,7 @@ struct pfn_info
#define PGT_l4_page_table (4<<29) /* using this page as an L4 page table? */
#define PGT_gdt_page (5<<29) /* using this page in a GDT? */
#define PGT_ldt_page (6<<29) /* using this page in an LDT? */
#define PGT_writeable_page (7<<29) /* has writable mappings of this page? */
#define PGT_writable_page (7<<29) /* has writable mappings of this page? */
#define PGT_type_mask (7<<29) /* Bits 29-31. */
/* Has this page been validated for use as its current type? */
#define _PGT_validated 28
@@ -101,8 +101,8 @@ struct pfn_info
#define SHARE_PFN_WITH_DOMAIN(_pfn, _dom) \
do { \
(_pfn)->u.inuse.domain = (_dom); \
/* The incremented type count is intended to pin to 'writeable'. */ \
(_pfn)->u.inuse.type_info = PGT_writeable_page | PGT_validated | 1;\
/* The incremented type count is intended to pin to 'writable'. */ \
(_pfn)->u.inuse.type_info = PGT_writable_page | PGT_validated | 1; \
wmb(); /* install valid domain ptr before updating refcnt. */ \
spin_lock(&(_dom)->page_alloc_lock); \
/* _dom holds an allocation reference */ \
@@ -221,8 +221,8 @@ static inline int get_page_type(struct pfn_info *page, u32 type)
{
nx &= ~(PGT_type_mask | PGT_validated);
nx |= type;
/* No extra validation needed for writeable pages. */
if ( type == PGT_writeable_page )
/* No extra validation needed for writable pages. */
if ( type == PGT_writable_page )
nx |= PGT_validated;
}
}
@@ -364,7 +364,7 @@ void ptwr_reconnect_disconnected(unsigned long addr);
void ptwr_flush_inactive(void);
int ptwr_do_page_fault(unsigned long);
static inline void cleanup_writable_pagetable(const int what)
static inline void __cleanup_writable_pagetable(const int what)
{
int cpu = smp_processor_id();
@@ -376,4 +376,10 @@ static inline void cleanup_writable_pagetable(const int what)
ptwr_flush_inactive();
}
static inline void cleanup_writable_pagetable(struct domain *d, const int what)
{
if ( unlikely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
__cleanup_writable_pagetable(what);
}
#endif /* __ASM_X86_MM_H__ */
-4
View File
@@ -244,10 +244,6 @@ struct i387_state {
u8 state[512]; /* big enough for FXSAVE */
} __attribute__ ((aligned (16)));
typedef struct {
unsigned long seg;
} mm_segment_t;
struct tss_struct {
unsigned short back_link,__blh;
#ifdef __x86_64__
+287 -468
View File
@@ -6,54 +6,65 @@
*/
#include <xen/config.h>
#include <xen/errno.h>
#include <xen/sched.h>
#include <xen/prefetch.h>
#include <asm/page.h>
#include <xen/string.h>
#include <xen/sched.h>
/* No user-pointer checking. */
#define __user
#define __chk_user_ptr(_p) ((void)0)
#define VERIFY_READ 0
#define VERIFY_WRITE 1
/*
* The fs value determines whether argument validity checking should be
* performed or not. If get_fs() == USER_DS, checking is performed, with
* get_fs() == KERNEL_DS, checking is bypassed.
*
* For historical reasons, these macros are grossly misnamed.
* movsl can be slow when source and dest are not both 8-byte aligned
*/
#ifdef CONFIG_X86_INTEL_USERCOPY
extern struct movsl_mask {
int mask;
} ____cacheline_aligned_in_smp movsl_mask;
#endif
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
#define get_ds() (KERNEL_DS)
#define get_fs() (current->addr_limit)
#define set_fs(x) (current->addr_limit = (x))
#define segment_eq(a,b) ((a).seg == (b).seg)
extern int __verify_write(const void *, unsigned long);
#define __addr_ok(addr) ((unsigned long)(addr) < (current->addr_limit.seg))
#define __addr_ok(addr) ((unsigned long)(addr) < HYPERVISOR_VIRT_START)
/*
* Uhhuh, this needs 33-bit arithmetic. We have a carry..
* Test whether a block of memory is a valid user space address.
* Returns 0 if the range is valid, nonzero otherwise.
*
* This is equivalent to the following test:
* (u33)addr + (u33)size >= (u33)HYPERVISOR_VIRT_START
*
* This needs 33-bit arithmetic. We have a carry...
*/
#define __range_ok(addr,size) ({ \
unsigned long flag,sum; \
__chk_user_ptr(addr); \
asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
:"=&r" (flag), "=r" (sum) \
:"1" (addr),"g" ((int)(size)),"g" (current->addr_limit.seg)); \
:"1" (addr),"g" ((int)(size)),"r" (HYPERVISOR_VIRT_START)); \
flag; })
#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
static inline int verify_area(int type, const void * addr, unsigned long size)
{
return access_ok(type,addr,size) ? 0 : -EFAULT;
}
/**
* access_ok: - Checks if a user space pointer is valid
* @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
* %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
* to write to a block, it is always safe to read from it.
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
* Context: User context only. This function may sleep.
*
* Checks if a pointer to a block of memory in user space is valid.
*
* Returns true (nonzero) if the memory block may be valid, false (zero)
* if it is definitely invalid.
*
* Note that, depending on architecture, this function probably just
* checks that the pointer is in the user space range - after calling
* this function, memory access functions may still return -EFAULT.
*/
#define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
/*
* The exception table consists of pairs of addresses: the first is the
@@ -73,81 +84,110 @@ struct exception_table_entry
unsigned long insn, fixup;
};
/* Returns 0 if exception not found and fixup otherwise. */
extern unsigned long search_exception_table(unsigned long);
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
/**
* get_user: - Get a simple variable from user space.
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
* This gets kind of ugly. We want to return _two_ values in "get_user()"
* and yet we don't want to do any pointers, because that is too much
* of a performance impact. Thus we have a few rather ugly macros here,
* and hide all the uglyness from the user.
* Context: User context only. This function may sleep.
*
* The "__xxx" versions of the user access functions are versions that
* do not verify the address space, that must have been done previously
* with a separate "access_ok()" call (this is used when we do multiple
* accesses to the same area of user memory).
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and the result of
* dereferencing @ptr must be assignable to @x without a cast.
*
* Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero.
*/
extern void __get_user_1(void);
extern void __get_user_2(void);
extern void __get_user_4(void);
#define __get_user_x(size,ret,x,ptr) \
__asm__ __volatile__("call __get_user_" #size \
:"=a" (ret),"=d" (x) \
:"0" (ptr))
/* Careful: we have to cast the result to the type of the pointer for sign reasons */
#define get_user(x,ptr) \
({ int __ret_gu=1,__val_gu; \
switch(sizeof (*(ptr))) { \
case 1: __ret_gu=copy_from_user(&__val_gu,ptr,1); break; \
case 2: __ret_gu=copy_from_user(&__val_gu,ptr,2); break; \
case 4: __ret_gu=copy_from_user(&__val_gu,ptr,4); break; \
default: __ret_gu=copy_from_user(&__val_gu,ptr,8); break; \
/*case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break;*/ \
/*case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break;*/ \
/*case 4: __get_user_x(4,__ret_gu,__val_gu,ptr); break;*/ \
/*default: __get_user_x(X,__ret_gu,__val_gu,ptr); break;*/ \
} \
(x) = (__typeof__(*(ptr)))__val_gu; \
__ret_gu; \
})
extern void __put_user_1(void);
extern void __put_user_2(void);
extern void __put_user_4(void);
extern void __put_user_8(void);
#define get_user(x,ptr) \
__get_user_check((x),(ptr),sizeof(*(ptr)))
extern void __put_user_bad(void);
/**
* put_user: - Write a simple value into user space.
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
* Context: User context only. This function may sleep.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
* to the result of dereferencing @ptr.
*
* Returns zero on success, or -EFAULT on error.
*/
#define put_user(x,ptr) \
__put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
/**
* __get_user: - Get a simple variable from user space, with less checking.
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
* Context: User context only. This function may sleep.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and the result of
* dereferencing @ptr must be assignable to @x without a cast.
*
* Caller must check the pointer with access_ok() before calling this
* function.
*
* Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero.
*/
#define __get_user(x,ptr) \
__get_user_nocheck((x),(ptr),sizeof(*(ptr)))
/**
* __put_user: - Write a simple value into user space, with less checking.
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
* Context: User context only. This function may sleep.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
* to the result of dereferencing @ptr.
*
* Caller must check the pointer with access_ok() before calling this
* function.
*
* Returns zero on success, or -EFAULT on error.
*/
#define __put_user(x,ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
#define __put_user_nocheck(x,ptr,size) \
({ \
long __pu_err; \
__put_user_size((x),(ptr),(size),__pu_err); \
__pu_err; \
#define __put_user_nocheck(x,ptr,size) \
({ \
long __pu_err; \
__put_user_size((x),(ptr),(size),__pu_err,-EFAULT); \
__pu_err; \
})
#define __put_user_check(x,ptr,size) \
({ \
#define __put_user_check(x,ptr,size) \
({ \
long __pu_err = -EFAULT; \
__typeof__(*(ptr)) *__pu_addr = (ptr); \
if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
__put_user_size((x),__pu_addr,(size),__pu_err); \
__pu_err; \
__typeof__(*(ptr)) __user *__pu_addr = (ptr); \
if (__addr_ok(__pu_addr)) \
__put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT); \
__pu_err; \
})
#define __put_user_u64(x, addr, err) \
@@ -167,18 +207,33 @@ extern void __put_user_bad(void);
: "=r"(err) \
: "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
#define __put_user_size(x,ptr,size,retval) \
#ifdef CONFIG_X86_WP_WORKS_OK
#define __put_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
__chk_user_ptr(ptr); \
switch (size) { \
case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break; \
case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break; \
case 4: __put_user_asm(x,ptr,retval,"l","","ir"); break; \
case 8: __put_user_u64(x,ptr,retval); break; \
case 1: __put_user_asm(x,ptr,retval,"b","b","iq",errret);break; \
case 2: __put_user_asm(x,ptr,retval,"w","w","ir",errret);break; \
case 4: __put_user_asm(x,ptr,retval,"l","","ir",errret); break; \
case 8: __put_user_u64((__typeof__(*ptr))(x),ptr,retval); break;\
default: __put_user_bad(); \
} \
} while (0)
#else
#define __put_user_size(x,ptr,size,retval,errret) \
do { \
__typeof__(*(ptr)) __pus_tmp = x; \
retval = 0; \
\
if(unlikely(__copy_to_user_ll(ptr, &__pus_tmp, size) != 0)) \
retval = errret; \
} while (0)
#endif
struct __large_struct { unsigned long buf[100]; };
#define __m(x) (*(struct __large_struct *)(x))
@@ -187,414 +242,178 @@ struct __large_struct { unsigned long buf[100]; };
* we do not write to any memory gcc knows about, so there are no
* aliasing issues.
*/
#define __put_user_asm(x, addr, err, itype, rtype, ltype) \
__asm__ __volatile__( \
"1: mov"itype" %"rtype"1,%2\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movl %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 1b,3b\n" \
".previous" \
: "=r"(err) \
: ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err))
#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \
__asm__ __volatile__( \
"1: mov"itype" %"rtype"1,%2\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movl %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 1b,3b\n" \
".previous" \
: "=r"(err) \
: ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
#define __get_user_nocheck(x,ptr,size) \
({ \
long __gu_err, __gu_val; \
__get_user_size(__gu_val,(ptr),(size),__gu_err); \
__get_user_size(__gu_val,(ptr),(size),__gu_err,-EFAULT);\
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
#define __get_user_check(x,ptr,size) \
({ \
long __gu_err, __gu_val; \
__typeof__(*(ptr)) __user *__gu_addr = (ptr); \
__get_user_size(__gu_val,__gu_addr,(size),__gu_err,-EFAULT); \
(x) = (__typeof__(*(ptr)))__gu_val; \
if (!__addr_ok(__gu_addr)) __gu_err = -EFAULT; \
__gu_err; \
})
extern long __get_user_bad(void);
#define __get_user_size(x,ptr,size,retval) \
#define __get_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
__chk_user_ptr(ptr); \
switch (size) { \
case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break; \
case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break; \
case 4: __get_user_asm(x,ptr,retval,"l","","=r"); break; \
default: (x) = __get_user_bad(); \
case 1: __get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \
case 2: __get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \
case 4: __get_user_asm(x,ptr,retval,"l","","=r",errret);break; \
default: (x) = __get_user_bad(); \
} \
} while (0)
#define __get_user_asm(x, addr, err, itype, rtype, ltype) \
__asm__ __volatile__( \
"1: mov"itype" %2,%"rtype"1\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movl %3,%0\n" \
" xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 1b,3b\n" \
".previous" \
: "=r"(err), ltype (x) \
: "m"(__m(addr)), "i"(-EFAULT), "0"(err))
#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
__asm__ __volatile__( \
"1: mov"itype" %2,%"rtype"1\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movl %3,%0\n" \
" xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 1b,3b\n" \
".previous" \
: "=r"(err), ltype (x) \
: "m"(__m(addr)), "i"(errret), "0"(err))
unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n);
unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned long n);
/*
* Copy To/From Userspace
* Here we special-case 1, 2 and 4-byte copy_*_user invocations. On a fault
* we return the initial request size (1, 2 or 4), as copy_*_user should do.
* If a store crosses a page boundary and gets a fault, the x86 will not write
* anything, so this is accurate.
*/
/* Generic arbitrary sized copy. */
#define __copy_user(to,from,size) \
do { \
int __d0, __d1; \
__asm__ __volatile__( \
"0: rep; movsl\n" \
" movl %3,%0\n" \
"1: rep; movsb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: lea 0(%3,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,3b\n" \
" .long 1b,2b\n" \
".previous" \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1) \
: "r"(size & 3), "0"(size / 4), "1"(to), "2"(from) \
: "memory"); \
} while (0)
#define __copy_user_zeroing(to,from,size) \
do { \
int __d0, __d1; \
__asm__ __volatile__( \
"0: rep; movsl\n" \
" movl %3,%0\n" \
"1: rep; movsb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: lea 0(%3,%0,4),%0\n" \
"4: pushl %0\n" \
" pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" rep; stosb\n" \
" popl %%eax\n" \
" popl %0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,3b\n" \
" .long 1b,4b\n" \
".previous" \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1) \
: "r"(size & 3), "0"(size / 4), "1"(to), "2"(from) \
: "memory"); \
} while (0)
/* We let the __ versions of copy_from/to_user inline, because they're often
* used in fast paths and have only a small space overhead.
/**
* __copy_to_user: - Copy a block of data into user space, with less checking.
* @to: Destination address, in user space.
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*/
static inline unsigned long
__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
__copy_user_zeroing(to,from,n);
return n;
if (__builtin_constant_p(n)) {
unsigned long ret;
switch (n) {
case 1:
__put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret, 1);
return ret;
case 2:
__put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret, 2);
return ret;
case 4:
__put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret, 4);
return ret;
}
}
return __copy_to_user_ll(to, from, n);
}
/**
* __copy_from_user: - Copy a block of data from user space, with less checking.
* @to: Destination address, in kernel space.
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from user space to kernel space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*
* If some data could not be copied, this function will pad the copied
* data to the requested size using zero bytes.
*/
static inline unsigned long
__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
__copy_from_user(void *to, const void __user *from, unsigned long n)
{
__copy_user(to,from,n);
return n;
if (__builtin_constant_p(n)) {
unsigned long ret;
switch (n) {
case 1:
__get_user_size(*(u8 *)to, from, 1, ret, 1);
return ret;
case 2:
__get_user_size(*(u16 *)to, from, 2, ret, 2);
return ret;
case 4:
__get_user_size(*(u32 *)to, from, 4, ret, 4);
return ret;
}
}
return __copy_from_user_ll(to, from, n);
}
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
unsigned long copy_from_user(void *to,
const void __user *from, unsigned long n);
long strncpy_from_user(char *dst, const char __user *src, long count);
long __strncpy_from_user(char *dst, const char __user *src, long count);
/* Optimize just a little bit when we know the size of the move. */
#define __constant_copy_user(to, from, size) \
do { \
int __d0, __d1; \
switch (size & 3) { \
default: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1:\n" \
".section .fixup,\"ax\"\n" \
"2: shl $2,%0\n" \
" jmp 1b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,2b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
case 1: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1: movsb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: shl $2,%0\n" \
"4: incl %0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,3b\n" \
" .long 1b,4b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
case 2: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1: movsw\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: shl $2,%0\n" \
"4: addl $2,%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,3b\n" \
" .long 1b,4b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
case 3: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1: movsw\n" \
"2: movsb\n" \
"3:\n" \
".section .fixup,\"ax\"\n" \
"4: shl $2,%0\n" \
"5: addl $2,%0\n" \
"6: incl %0\n" \
" jmp 3b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,4b\n" \
" .long 1b,5b\n" \
" .long 2b,6b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
} \
} while (0)
/* Optimize just a little bit when we know the size of the move. */
#define __constant_copy_user_zeroing(to, from, size) \
do { \
int __d0, __d1; \
switch (size & 3) { \
default: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1:\n" \
".section .fixup,\"ax\"\n" \
"2: pushl %0\n" \
" pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" rep; stosl\n" \
" popl %%eax\n" \
" popl %0\n" \
" shl $2,%0\n" \
" jmp 1b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,2b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
case 1: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1: movsb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: pushl %0\n" \
" pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" rep; stosl\n" \
" stosb\n" \
" popl %%eax\n" \
" popl %0\n" \
" shl $2,%0\n" \
" incl %0\n" \
" jmp 2b\n" \
"4: pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" stosb\n" \
" popl %%eax\n" \
" incl %0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,3b\n" \
" .long 1b,4b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
case 2: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1: movsw\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: pushl %0\n" \
" pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" rep; stosl\n" \
" stosw\n" \
" popl %%eax\n" \
" popl %0\n" \
" shl $2,%0\n" \
" addl $2,%0\n" \
" jmp 2b\n" \
"4: pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" stosw\n" \
" popl %%eax\n" \
" addl $2,%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,3b\n" \
" .long 1b,4b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
case 3: \
__asm__ __volatile__( \
"0: rep; movsl\n" \
"1: movsw\n" \
"2: movsb\n" \
"3:\n" \
".section .fixup,\"ax\"\n" \
"4: pushl %0\n" \
" pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" rep; stosl\n" \
" stosw\n" \
" stosb\n" \
" popl %%eax\n" \
" popl %0\n" \
" shl $2,%0\n" \
" addl $3,%0\n" \
" jmp 2b\n" \
"5: pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" stosw\n" \
" stosb\n" \
" popl %%eax\n" \
" addl $3,%0\n" \
" jmp 2b\n" \
"6: pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" stosb\n" \
" popl %%eax\n" \
" incl %0\n" \
" jmp 3b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,4b\n" \
" .long 1b,5b\n" \
" .long 2b,6b\n" \
".previous" \
: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
: "1"(from), "2"(to), "0"(size/4) \
: "memory"); \
break; \
} \
} while (0)
unsigned long __generic_copy_to_user(void *, const void *, unsigned long);
unsigned long __generic_copy_from_user(void *, const void *, unsigned long);
static inline unsigned long
__constant_copy_to_user(void *to, const void *from, unsigned long n)
{
prefetch(from);
if (access_ok(VERIFY_WRITE, to, n))
__constant_copy_user(to,from,n);
return n;
}
static inline unsigned long
__constant_copy_from_user(void *to, const void *from, unsigned long n)
{
if (access_ok(VERIFY_READ, from, n))
__constant_copy_user_zeroing(to,from,n);
else
memset(to, 0, n);
return n;
}
static inline unsigned long
__constant_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
{
__constant_copy_user(to,from,n);
return n;
}
static inline unsigned long
__constant_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
{
__constant_copy_user_zeroing(to,from,n);
return n;
}
#define copy_to_user(to,from,n) \
(__builtin_constant_p(n) ? \
__constant_copy_to_user((to),(from),(n)) : \
__generic_copy_to_user((to),(from),(n)))
#define copy_from_user(to,from,n) \
(__builtin_constant_p(n) ? \
__constant_copy_from_user((to),(from),(n)) : \
__generic_copy_from_user((to),(from),(n)))
#define __copy_to_user(to,from,n) \
(__builtin_constant_p(n) ? \
__constant_copy_to_user_nocheck((to),(from),(n)) : \
__generic_copy_to_user_nocheck((to),(from),(n)))
#define __copy_from_user(to,from,n) \
(__builtin_constant_p(n) ? \
__constant_copy_from_user_nocheck((to),(from),(n)) : \
__generic_copy_from_user_nocheck((to),(from),(n)))
long strncpy_from_user(char *dst, const char *src, long count);
long __strncpy_from_user(char *dst, const char *src, long count);
/**
* strlen_user: - Get the size of a string in user space.
* @str: The string to measure.
*
* Context: User context only. This function may sleep.
*
* Get the size of a NUL-terminated string in user space.
*
* Returns the size of the string INCLUDING the terminating NUL.
* On exception, returns 0.
*
* If there is a limit on the length of a valid string, you may wish to
* consider using strnlen_user() instead.
*/
#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
long strnlen_user(const char *str, long n);
unsigned long clear_user(void *mem, unsigned long len);
unsigned long __clear_user(void *mem, unsigned long len);
long strnlen_user(const char __user *str, long n);
unsigned long clear_user(void __user *mem, unsigned long len);
unsigned long __clear_user(void __user *mem, unsigned long len);
#endif /* __i386_UACCESS_H */
+109 -64
View File
@@ -4,10 +4,11 @@
/*
* User space memory access functions
*/
#include <xen/config.h>
#include <xen/sched.h>
#include <xen/prefetch.h>
#include <xen/errno.h>
#include <linux/config.h>
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/prefetch.h>
#include <asm/page.h>
#define VERIFY_READ 0
@@ -23,31 +24,32 @@
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFFFFFFFFF)
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFFFFFFFFFUL)
#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
#define get_ds() (KERNEL_DS)
#define get_fs() (current->addr_limit)
#define set_fs(x) (current->addr_limit = (x))
#define get_fs() (current_thread_info()->addr_limit)
#define set_fs(x) (current_thread_info()->addr_limit = (x))
#define segment_eq(a,b) ((a).seg == (b).seg)
#define __addr_ok(addr) (!((unsigned long)(addr) & (current->addr_limit.seg)))
#define __addr_ok(addr) (!((unsigned long)(addr) & (current_thread_info()->addr_limit.seg)))
/*
* Uhhuh, this needs 65-bit arithmetic. We have a carry..
*/
#define __range_not_ok(addr,size) ({ \
unsigned long flag,sum; \
__chk_user_ptr(addr); \
asm("# range_ok\n\r" \
"addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \
:"=&r" (flag), "=r" (sum) \
:"1" (addr),"g" ((long)(size)),"g" (current->addr_limit.seg)); \
:"1" (addr),"g" ((long)(size)),"g" (current_thread_info()->addr_limit.seg)); \
flag; })
#define access_ok(type,addr,size) (__range_not_ok(addr,size) == 0)
#define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
extern inline int verify_area(int type, const void * addr, unsigned long size)
extern inline int verify_area(int type, const void __user * addr, unsigned long size)
{
return access_ok(type,addr,size) ? 0 : -EFAULT;
}
@@ -101,12 +103,13 @@ extern void __get_user_8(void);
/* Careful: we have to cast the result to the type of the pointer for sign reasons */
#define get_user(x,ptr) \
({ long __val_gu; \
int __ret_gu=1; \
int __ret_gu; \
__chk_user_ptr(ptr); \
switch(sizeof (*(ptr))) { \
case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \
case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \
case 4: __get_user_x(4,__ret_gu,__val_gu,ptr); break; \
case 8: __get_user_x(8,__ret_gu,__val_gu,ptr); break; \
case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \
case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \
case 4: __get_user_x(4,__ret_gu,__val_gu,ptr); break; \
case 8: __get_user_x(8,__ret_gu,__val_gu,ptr); break; \
default: __get_user_bad(); break; \
} \
(x) = (__typeof__(*(ptr)))__val_gu; \
@@ -145,8 +148,8 @@ extern void __put_user_bad(void);
#define __put_user_check(x,ptr,size) \
({ \
int __pu_err = -EFAULT; \
__typeof__(*(ptr)) *__pu_addr = (ptr); \
if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
__typeof__(*(ptr)) __user *__pu_addr = (ptr); \
if (likely(access_ok(VERIFY_WRITE,__pu_addr,size))) \
__put_user_size((x),__pu_addr,(size),__pu_err); \
__pu_err; \
})
@@ -154,6 +157,7 @@ extern void __put_user_bad(void);
#define __put_user_size(x,ptr,size,retval) \
do { \
retval = 0; \
__chk_user_ptr(ptr); \
switch (size) { \
case 1: __put_user_asm(x,ptr,retval,"b","b","iq",-EFAULT); break;\
case 2: __put_user_asm(x,ptr,retval,"w","w","ir",-EFAULT); break;\
@@ -173,18 +177,18 @@ struct __large_struct { unsigned long buf[100]; };
* aliasing issues.
*/
#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno) \
__asm__ __volatile__( \
"1: mov"itype" %"rtype"1,%2\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
__asm__ __volatile__( \
"1: mov"itype" %"rtype"1,%2\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: mov %3,%0\n" \
" jmp 2b\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 8\n" \
".section __ex_table,\"a\"\n" \
" .align 8\n" \
" .quad 1b,3b\n" \
".previous" \
: "=r"(err) \
".previous" \
: "=r"(err) \
: ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
@@ -202,6 +206,7 @@ extern int __get_user_bad(void);
#define __get_user_size(x,ptr,size,retval) \
do { \
retval = 0; \
__chk_user_ptr(ptr); \
switch (size) { \
case 1: __get_user_asm(x,ptr,retval,"b","b","=q",-EFAULT); break;\
case 2: __get_user_asm(x,ptr,retval,"w","w","=r",-EFAULT); break;\
@@ -234,76 +239,116 @@ do { \
/* Handles exceptions in both to and from, but doesn't do access_ok */
extern unsigned long copy_user_generic(void *to, const void *from, unsigned len);
extern unsigned long copy_to_user(void *to, const void *from, unsigned len);
extern unsigned long copy_from_user(void *to, const void *from, unsigned len);
extern unsigned long copy_to_user(void __user *to, const void *from, unsigned len);
extern unsigned long copy_from_user(void *to, const void __user *from, unsigned len);
extern unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len);
static inline int __copy_from_user(void *dst, const void *src, unsigned size)
static inline int __copy_from_user(void *dst, const void __user *src, unsigned size)
{
int ret = 0;
if (!__builtin_constant_p(size))
return copy_user_generic(dst,src,size);
int ret = 0;
return copy_user_generic(dst,(__force void *)src,size);
switch (size) {
case 1:__get_user_asm(*(u8*)dst,(u8 *)src,ret,"b","b","=q",1);
case 1:__get_user_asm(*(u8*)dst,(u8 __user *)src,ret,"b","b","=q",1);
return ret;
case 2:__get_user_asm(*(u16*)dst,(u16*)src,ret,"w","w","=r",2);
case 2:__get_user_asm(*(u16*)dst,(u16 __user *)src,ret,"w","w","=r",2);
return ret;
case 4:__get_user_asm(*(u32*)dst,(u32*)src,ret,"l","k","=r",4);
case 4:__get_user_asm(*(u32*)dst,(u32 __user *)src,ret,"l","k","=r",4);
return ret;
case 8:__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",8);
case 8:__get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",8);
return ret;
case 10:
__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16);
if (ret) return ret;
__get_user_asm(*(u16*)(8+dst),(u16*)(8+src),ret,"w","w","=r",2);
__get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
if (unlikely(ret)) return ret;
__get_user_asm(*(u16*)(8+(char*)dst),(u16 __user *)(8+(char __user *)src),ret,"w","w","=r",2);
return ret;
case 16:
__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16);
if (ret) return ret;
__get_user_asm(*(u64*)(8+dst),(u64*)(8+src),ret,"q","","=r",8);
__get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
if (unlikely(ret)) return ret;
__get_user_asm(*(u64*)(8+(char*)dst),(u64 __user *)(8+(char __user *)src),ret,"q","","=r",8);
return ret;
default:
return copy_user_generic(dst,src,size);
return copy_user_generic(dst,(__force void *)src,size);
}
}
static inline int __copy_to_user(void *dst, const void *src, unsigned size)
static inline int __copy_to_user(void __user *dst, const void *src, unsigned size)
{
int ret = 0;
if (!__builtin_constant_p(size))
return copy_user_generic(dst,src,size);
int ret = 0;
return copy_user_generic((__force void *)dst,src,size);
switch (size) {
case 1:__put_user_asm(*(u8*)src,(u8 *)dst,ret,"b","b","iq",1);
case 1:__put_user_asm(*(u8*)src,(u8 __user *)dst,ret,"b","b","iq",1);
return ret;
case 2:__put_user_asm(*(u16*)src,(u16*)dst,ret,"w","w","ir",2);
case 2:__put_user_asm(*(u16*)src,(u16 __user *)dst,ret,"w","w","ir",2);
return ret;
case 4:__put_user_asm(*(u32*)src,(u32*)dst,ret,"l","k","ir",4);
case 4:__put_user_asm(*(u32*)src,(u32 __user *)dst,ret,"l","k","ir",4);
return ret;
case 8:__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",8);
case 8:__put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",8);
return ret;
case 10:
__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",10);
if (ret) return ret;
__put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",10);
if (unlikely(ret)) return ret;
asm("":::"memory");
__put_user_asm(4[(u16*)src],4+(u16*)dst,ret,"w","w","ir",2);
__put_user_asm(4[(u16*)src],4+(u16 __user *)dst,ret,"w","w","ir",2);
return ret;
case 16:
__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",16);
if (ret) return ret;
__put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",16);
if (unlikely(ret)) return ret;
asm("":::"memory");
__put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8);
__put_user_asm(1[(u64*)src],1+(u64 __user *)dst,ret,"q","","ir",8);
return ret;
default:
return copy_user_generic(dst,src,size);
return copy_user_generic((__force void *)dst,src,size);
}
}
long strncpy_from_user(char *dst, const char *src, long count);
long __strncpy_from_user(char *dst, const char *src, long count);
long strnlen_user(const char *str, long n);
long strlen_user(const char *str);
unsigned long clear_user(void *mem, unsigned long len);
unsigned long __clear_user(void *mem, unsigned long len);
extern unsigned long search_exception_table(unsigned long);
static inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
{
int ret = 0;
if (!__builtin_constant_p(size))
return copy_user_generic((__force void *)dst,(__force void *)src,size);
switch (size) {
case 1: {
u8 tmp;
__get_user_asm(tmp,(u8 __user *)src,ret,"b","b","=q",1);
if (likely(!ret))
__put_user_asm(tmp,(u8 __user *)dst,ret,"b","b","iq",1);
return ret;
}
case 2: {
u16 tmp;
__get_user_asm(tmp,(u16 __user *)src,ret,"w","w","=r",2);
if (likely(!ret))
__put_user_asm(tmp,(u16 __user *)dst,ret,"w","w","ir",2);
return ret;
}
case 4: {
u32 tmp;
__get_user_asm(tmp,(u32 __user *)src,ret,"l","k","=r",4);
if (likely(!ret))
__put_user_asm(tmp,(u32 __user *)dst,ret,"l","k","ir",4);
return ret;
}
case 8: {
u64 tmp;
__get_user_asm(tmp,(u64 __user *)src,ret,"q","","=r",8);
if (likely(!ret))
__put_user_asm(tmp,(u64 __user *)dst,ret,"q","","ir",8);
return ret;
}
default:
return copy_user_generic((__force void *)dst,(__force void *)src,size);
}
}
long strncpy_from_user(char *dst, const char __user *src, long count);
long __strncpy_from_user(char *dst, const char __user *src, long count);
long strnlen_user(const char __user *str, long n);
long strlen_user(const char __user *str);
unsigned long clear_user(void __user *mem, unsigned long len);
unsigned long __clear_user(void __user *mem, unsigned long len);
#endif /* __X86_64_UACCESS_H */
+69 -12
View File
@@ -5,8 +5,17 @@
* page-ownership transfers.
*
* Copyright (c) 2004, K A Fraser
*
* Some rough guidelines on accessing and updating grant-table entries
*/
#ifndef __HYPERVISOR_IFS_GRANT_TABLE_H__
#define __HYPERVISOR_IFS_GRANT_TABLE_H__
/***********************************
* GRANT TABLE REPRESENTATION
*/
/* Some rough guidelines on accessing and updating grant-table entries
* in a concurreny-safe manner. For more information, Linux contains a
* reference implementation for guest OSes (arch/xen/kernel/grant_table.c).
*
@@ -35,9 +44,6 @@
* Use SMP-safe bit-setting instruction.
*/
#ifndef __HYPERVISOR_IFS_GRANT_TABLE_H__
#define __HYPERVISOR_IFS_GRANT_TABLE_H__
/*
* A grant table comprises a packed array of grant entries in one or more
* page frames shared between Xen and a guest.
@@ -56,11 +62,6 @@ typedef struct {
u32 frame; /* 4 */
} PACKED grant_entry_t; /* 8 bytes */
/*
* Reference to a grant entry in a specified domain's grant table.
*/
typedef u16 grant_ref_t;
/*
* Type of grant entry.
* GTF_invalid: This grant entry grants no privileges.
@@ -82,8 +83,64 @@ typedef u16 grant_ref_t;
#define _GTF_readonly (2)
#define GTF_readonly (1<<_GTF_readonly)
#define _GTF_reading (3)
#define GTF_reading (1<<_GTF_inuse)
#define GTF_reading (1<<_GTF_reading)
#define _GTF_writing (4)
#define GTF_writing (1<<_GTF_inuse)
#define GTF_writing (1<<_GTF_writing)
/***********************************
* GRANT TABLE QUERIES AND USES
*/
/*
* Reference to a grant entry in a specified domain's grant table.
*/
typedef u16 grant_ref_t;
/*
* GNTTABOP_update_pin_status: Change the pin status of of <dom>'s grant entry
* with reference <ref>.
* NOTES:
* 1. If GNTPIN_dev_accessible 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.
*/
#define GNTTABOP_update_pin_status 0
typedef struct {
/* IN parameters. */
domid_t dom; /* 0 */
grant_ref_t ref; /* 2 */
u16 pin_flags; /* 4 */
u16 __pad; /* 6 */
/* OUT parameters. */
memory_t dev_bus_addr; /* 8 */
MEMORY_PADDING;
memory_t host_phys_addr; /* 12 */
MEMORY_PADDING;
} PACKED gnttab_update_pin_status_t; /* 16 bytes */
typedef struct {
u32 cmd; /* GNTTABOP_* */ /* 0 */
u32 __reserved; /* 4 */
union { /* 8 */
gnttab_update_pin_status_t update_pin_status;
u8 __dummy[16];
} PACKED u;
} PACKED gnttab_op_t; /* 24 bytes */
/*
* Bitfield values for <pin_flags>.
*/
/* 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)
#endif /* __HYPERVISOR_IFS_GRANT_TABLE_H__ */
+4 -3
View File
@@ -45,8 +45,9 @@
#define __HYPERVISOR_xen_version 17
#define __HYPERVISOR_console_io 18
#define __HYPERVISOR_physdev_op 19
#define __HYPERVISOR_update_va_mapping_otherdomain 20
#define __HYPERVISOR_grant_table_op 20
#define __HYPERVISOR_vm_assist 21
#define __HYPERVISOR_update_va_mapping_otherdomain 22
/*
* MULTICALLS
@@ -183,7 +184,7 @@
#define VMASST_CMD_disable 1
#define VMASST_TYPE_4gb_segments 0
#define VMASST_TYPE_4gb_segments_notify 1
#define VMASST_TYPE_writeable_pagetables 2
#define VMASST_TYPE_writable_pagetables 2
#define MAX_VMASST_TYPE 2
#ifndef __ASSEMBLY__
@@ -370,7 +371,7 @@ typedef struct shared_info_st
* 7. The list of page frames forms a contiguous 'pseudo-physical' memory
* layout for the domain. In particular, the bootstrap virtual-memory
* region is a 1:1 mapping to the first section of the pseudo-physical map.
* 8. All bootstrap elements are mapped read-writeable for the guest OS. The
* 8. All bootstrap elements are mapped read-writable for the guest OS. The
* only exception is the bootstrap page table, which is mapped read-only.
* 9. There is guaranteed to be at least 512kB padding after the final
* bootstrap element. If necessary, the bootstrap virtual region is
@@ -267,7 +267,7 @@ typedef struct {
u16 __pad;
u32 blkif_handle; /* 4: ...ditto... */
blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */
u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */
u16 readonly; /* 10: Non-zero -> VBD isn't writable. */
/* OUT */
u32 status; /* 12 */
} PACKED blkif_be_vbd_create_t; /* 16 bytes */
+2 -10
View File
@@ -10,6 +10,8 @@
#include <asm/config.h>
#define EXPORT_SYMBOL(var)
#define offsetof(_p,_f) ((unsigned long)&(((_p *)0)->_f))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* syslog levels ==> nothing! */
#define KERN_NOTICE ""
@@ -21,16 +23,6 @@
#define KERN_EMERG ""
#define KERN_ALERT ""
#define offsetof(_p,_f) ((unsigned long)&(((_p *)0)->_f))
#define struct_cpy(_x,_y) (memcpy((_x),(_y),sizeof(*(_x))))
#define dev_probe_lock() ((void)0)
#define dev_probe_unlock() ((void)0)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define capable(_c) 0
#ifdef VERBOSE
#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \
__FILE__ , __LINE__ , ## _a )
+39 -3
View File
@@ -24,9 +24,45 @@
#ifndef __XEN_GRANT_H__
#define __XEN_GRANT_H__
#ifndef __GRANT_TABLE_IMPLEMENTATION__
typedef void grant_table_t;
#endif
#include <hypervisor-ifs/grant_table.h>
/* 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. */
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)
/* 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 NR_GRANT_ENTRIES (PAGE_SIZE / sizeof(grant_entry_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. */
spinlock_t lock;
/* Hash table: frame -> active grant entry. */
u16 maphash[GNT_MAPHASH_SZ];
} grant_table_t;
/* Start-of-day system initialisation. */
void grant_table_init(void);
-2
View File
@@ -109,8 +109,6 @@ struct domain
struct mm_struct mm;
mm_segment_t addr_limit;
struct thread_struct thread;
struct domain *next_list, *next_hash;
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.