aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/xencomm.c
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2012-01-23 09:41:27 +0000
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>2012-01-23 09:41:27 +0000
commit7b8c36701d267971f189b435362bce8ff2266e79 (patch)
tree69e6db7b19474fada930ed0a9be2acd31c808d3f /xen/common/xencomm.c
parent02a59232513240899da538380010accf3d24f687 (diff)
downloadxen-7b8c36701d267971f189b435362bce8ff2266e79.tar.gz
xen-7b8c36701d267971f189b435362bce8ff2266e79.tar.bz2
xen-7b8c36701d267971f189b435362bce8ff2266e79.zip
Introduce clear_user and clear_guest
Introduce clear_user for x86 and ia64, shamelessly taken from Linux. The x86 version is the 32 bit clear_user implementation. Introduce clear_guest for x86 and ia64. The x86 implementation is based on clear_user and a new clear_user_hvm function. The ia64 implementation is actually in xencomm and it is based on xencomm_copy_to_guest. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Jan Beulich <JBeulich@suse.com> Committed-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/common/xencomm.c')
-rw-r--r--xen/common/xencomm.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/xen/common/xencomm.c b/xen/common/xencomm.c
index 247545494d..9f6c1c5e9e 100644
--- a/xen/common/xencomm.c
+++ b/xen/common/xencomm.c
@@ -414,6 +414,117 @@ out:
return n - from_pos;
}
+static int
+xencomm_clear_chunk(
+ unsigned long paddr, unsigned int len)
+{
+ struct page_info *page;
+ int res;
+
+ do {
+ res = xencomm_get_page(paddr, &page);
+ } while ( res == -EAGAIN );
+
+ if ( res )
+ return res;
+
+ memset(xencomm_vaddr(paddr, page), 0x00, len);
+ xencomm_mark_dirty((unsigned long)xencomm_vaddr(paddr, page), len);
+ put_page(page);
+
+ return 0;
+}
+
+static unsigned long
+xencomm_inline_clear_guest(
+ void *to, unsigned int n, unsigned int skip)
+{
+ unsigned long dest_paddr = xencomm_inline_addr(to) + skip;
+
+ while ( n > 0 )
+ {
+ unsigned int chunksz, bytes;
+
+ chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
+ bytes = min(chunksz, n);
+
+ if ( xencomm_clear_chunk(dest_paddr, bytes) )
+ return n;
+ dest_paddr += bytes;
+ n -= bytes;
+ }
+
+ /* Always successful. */
+ return 0;
+}
+
+/**
+ * xencomm_clear_guest: Clear a block of data in domain space.
+ * @to: Physical address to xencomm buffer descriptor.
+ * @n: Number of bytes to copy.
+ * @skip: Number of bytes from the start to skip.
+ *
+ * Clear domain data
+ *
+ * Returns number of bytes that could not be cleared
+ * On success, this will be zero.
+ */
+unsigned long
+xencomm_clear_guest(
+ void *to, unsigned int n, unsigned int skip)
+{
+ struct xencomm_ctxt ctxt;
+ unsigned int from_pos = 0;
+ unsigned int to_pos = 0;
+ unsigned int i = 0;
+
+ if ( xencomm_is_inline(to) )
+ return xencomm_inline_clear_guest(to, n, skip);
+
+ if ( xencomm_ctxt_init(to, &ctxt) )
+ return n;
+
+ /* Iterate through the descriptor, copying up to a page at a time */
+ while ( (from_pos < n) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
+ {
+ unsigned long dest_paddr;
+ unsigned int pgoffset, chunksz, chunk_skip;
+
+ if ( xencomm_ctxt_next(&ctxt, i) )
+ goto out;
+ dest_paddr = *xencomm_ctxt_address(&ctxt);
+ if ( dest_paddr == XENCOMM_INVALID )
+ {
+ i++;
+ continue;
+ }
+
+ pgoffset = dest_paddr % PAGE_SIZE;
+ chunksz = PAGE_SIZE - pgoffset;
+
+ chunk_skip = min(chunksz, skip);
+ to_pos += chunk_skip;
+ chunksz -= chunk_skip;
+ skip -= chunk_skip;
+
+ if ( skip == 0 && chunksz > 0 )
+ {
+ unsigned int bytes = min(chunksz, n - from_pos);
+
+ if ( xencomm_clear_chunk(dest_paddr + chunk_skip, bytes) )
+ goto out;
+ from_pos += bytes;
+ to_pos += bytes;
+ }
+
+ i++;
+ }
+
+out:
+ xencomm_ctxt_done(&ctxt);
+ return n - from_pos;
+}
+
static int xencomm_inline_add_offset(void **handle, unsigned int bytes)
{
*handle += bytes;