diff -r cf3c717101a8 -r a64ebf373f9c linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Wed Nov 23 15:13:22 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Wed Nov 23 15:38:27 2005 @@ -4,3 +4,5 @@ xenidc-objs += xenidc_callback.o xenidc-objs += xenidc_work.o xenidc-objs += xenidc_buffer_resource_provider.o +xenidc-objs += xenidc_local_buffer_reference.o +xenidc-objs += xenidc_remote_buffer_reference.o diff -r cf3c717101a8 -r a64ebf373f9c linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c --- /dev/null Wed Nov 23 15:13:22 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c Wed Nov 23 15:38:27 2005 @@ -0,0 +1,385 @@ +/*****************************************************************************/ +/* Xen inter-domain communication local buffer references. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include "xenidc_trace.h" + +#define XENIDC_LBR_HASH_COUNT 255 +static DEFINE_RWLOCK(xenidc_lbr_lock); +static struct list_head xenidc_lbr_concrete_hash[XENIDC_LBR_HASH_COUNT]; +static struct list_head xenidc_lbr_copy_hash[XENIDC_LBR_HASH_COUNT]; +static struct list_head xenidc_lbr_virtual_hash[XENIDC_LBR_HASH_COUNT]; + +static void xenidc_lbr_init(void) +{ + static int initialised = 0; + unsigned long flags; + trace(); + write_lock_irqsave(&xenidc_lbr_lock, flags); + if (!initialised) { + int i; + for (i = 0; i < XENIDC_LBR_HASH_COUNT; i++) { + INIT_LIST_HEAD(&xenidc_lbr_concrete_hash[i]); + INIT_LIST_HEAD(&xenidc_lbr_copy_hash[i]); + INIT_LIST_HEAD(&xenidc_lbr_virtual_hash[i]); + } + initialised = 1; + } + write_unlock_irqrestore(&xenidc_lbr_lock,flags); +} + +static void +xenidc_lbr_default_zero(struct xenidc_lbr_concrete_class *class, +struct xenidc_lbr *lbr) +{ + struct xenidc_lbr temp_lbr = *lbr; + u8 buffer[64]; + trace(); + memset(buffer, 0, 64); + do { + xenidc_buffer_byte_count this_go = + min(temp_lbr.byte_count, (xenidc_buffer_byte_count)64); + class->copy_in_or_out(class, &temp_lbr, buffer, this_go, 0); + xenidc_lbr_advance(&temp_lbr, this_go); + } while (temp_lbr.byte_count != 0); +} + +xenidc_lbr_type +xenidc_lbr_register_concrete_class(struct xenidc_lbr_concrete_class *class, +xenidc_lbr_copy_in_or_out_function *copy_in_or_out, +xenidc_lbr_zero_function *zero, +xenidc_lbr_calculate_rbr_resources_function *calculate_rbr_resources, +xenidc_lbr_create_rbr_function *create_rbr, +xenidc_lbr_revoke_rbr_function *revoke_rbr) +{ + static xenidc_lbr_type type_index = 0; + unsigned long flags; + trace(); + xenidc_lbr_init(); + INIT_LIST_HEAD(&class->link); + if (zero == NULL) + zero = xenidc_lbr_default_zero; + class->copy_in_or_out = copy_in_or_out; + class->zero = zero; + class->calculate_rbr_resources = calculate_rbr_resources; + class->create_rbr = create_rbr; + class->revoke_rbr = revoke_rbr; + write_lock_irqsave(&xenidc_lbr_lock, flags); + class->type = ++type_index; + list_add_tail(&class->link, &xenidc_lbr_concrete_hash[ + class->type % XENIDC_LBR_HASH_COUNT]); + write_unlock_irqrestore(&xenidc_lbr_lock, flags); + return class->type; +} + +static inline struct xenidc_lbr_concrete_class * +xenidc_lbr_find_concrete_class(xenidc_lbr_type type) +{ + int i = type % XENIDC_LBR_HASH_COUNT; + struct xenidc_lbr_concrete_class *class; + unsigned long flags; + trace(); + read_lock_irqsave(&xenidc_lbr_lock, flags); + list_for_each_entry(class, &xenidc_lbr_concrete_hash[i], link) { + if (class->type == type) { + read_unlock_irqrestore(&xenidc_lbr_lock, flags); + return class; + } + } + read_unlock_irqrestore(&xenidc_lbr_lock, flags); + BUG(); + return NULL; +} + +void +xenidc_lbr_register_copy_class(struct xenidc_lbr_copy_class *class, +xenidc_lbr_type target_type, xenidc_lbr_type source_type, +xenidc_lbr_copy_function *copy) +{ + unsigned long flags; + int i = ((target_type << 16 | source_type) % XENIDC_LBR_HASH_COUNT); + trace(); + INIT_LIST_HEAD(&class->link); + class->target_type = target_type; + class->source_type = source_type; + class->copy = copy; + write_lock_irqsave(&xenidc_lbr_lock, flags); + list_add_tail(&class->link, &xenidc_lbr_copy_hash[i]); + write_unlock_irqrestore(&xenidc_lbr_lock, flags); +} + +static inline struct xenidc_lbr_copy_class * +xenidc_lbr_find_copy_class(xenidc_lbr_type target_type, +xenidc_lbr_type source_type) +{ + int i = ((target_type << 16 | source_type) % XENIDC_LBR_HASH_COUNT); + struct xenidc_lbr_copy_class *class; + unsigned long flags; + trace(); + read_lock_irqsave(&xenidc_lbr_lock, flags); + list_for_each_entry(class, &xenidc_lbr_copy_hash[i], link) { + if ((class->target_type == target_type) && + (class->source_type == source_type)) { + read_unlock_irqrestore(&xenidc_lbr_lock, flags); + return class; + } + } + read_unlock_irqrestore(&xenidc_lbr_lock, flags); + return NULL; +} + +xenidc_lbr_type +xenidc_lbr_register_virtual_class(struct xenidc_lbr_virtual_class *class, +xenidc_lbr_resolve_function *resolve, +xenidc_lbr_advance_function *advance) +{ + static xenidc_lbr_type type_index = 0; + unsigned long flags; + trace(); + xenidc_lbr_init(); + INIT_LIST_HEAD(&class->link); + class->resolve = resolve; + class->advance = advance; + write_lock_irqsave(&xenidc_lbr_lock, flags); + class->type = ++type_index | XENIDC_LBR_TYPE_FLAG_VIRTUAL | + ((advance != NULL) ? XENIDC_LBR_TYPE_FLAG_VIRTUAL_ADVANCE : 0); + list_add_tail(&class->link, &xenidc_lbr_virtual_hash + [class->type % XENIDC_LBR_HASH_COUNT]); + write_unlock_irqrestore(&xenidc_lbr_lock, flags); + return class->type; +} + +static inline struct xenidc_lbr_virtual_class * +xenidc_lbr_find_virtual_class(xenidc_lbr_type type) +{ + int i = type % XENIDC_LBR_HASH_COUNT; + struct xenidc_lbr_virtual_class *class; + unsigned long flags; + trace(); + read_lock_irqsave(&xenidc_lbr_lock, flags); + list_for_each_entry(class, &xenidc_lbr_virtual_hash[i], link) { + if (class->type == type) { + read_unlock_irqrestore(&xenidc_lbr_lock, flags); + return class; + } + } + read_unlock_irqrestore(&xenidc_lbr_lock, flags); + BUG(); + return NULL; +} + +struct xenidc_lbr xenidc_lbr_resolve(struct xenidc_lbr *lbr) +{ + struct xenidc_lbr resolved_lbr = *lbr; + trace(); + while (1) { + if ((resolved_lbr.type & XENIDC_LBR_TYPE_FLAG_VIRTUAL) == 0) { + return resolved_lbr; + } else { + struct xenidc_lbr_virtual_class *class = + xenidc_lbr_find_virtual_class(resolved_lbr.type); + resolved_lbr = class->resolve(class, &resolved_lbr); + } + } +} + +int +xenidc_lbr_calculate_rbr_resources(struct xenidc_lbr *lbr, +struct xenidc_address *address, struct xenidc_buffer_resource_list *list) +{ + trace(); + if (lbr->byte_count != 0) { + struct xenidc_lbr_concrete_class *class; + class = xenidc_lbr_find_concrete_class(lbr->type); + return class->calculate_rbr_resources(class, lbr, address, + list); + } else { + *list = xenidc_buffer_resource_list_null(); + return 0; + } +} + +struct xenidc_lbr_concrete_class ** +xenidc_lbr_create_rbr(struct xenidc_lbr *lbr, struct xenidc_address *address, +struct xenidc_buffer_resource_provider *provider, struct xenidc_rbr *rbr, +int access_flags) +{ + trace(); + if (lbr->byte_count != 0) { + struct xenidc_lbr_concrete_class *class; + class = xenidc_lbr_find_concrete_class(lbr->type); + return class->create_rbr(class, lbr, address, provider, rbr, + access_flags); + } else { + memset(rbr, 0, sizeof(*rbr)); + return NULL; + } +} + +void +xenidc_lbr_revoke_rbr(struct xenidc_lbr_concrete_class **context, +struct xenidc_callback *callback) +{ + trace(); + if (context != NULL) { + (*context)->revoke_rbr(context, callback); + } else { + xenidc_callback_success(callback); + } +} + +xenidc_buffer_byte_count +xenidc_lbr_copy_in_or_out(struct xenidc_lbr *lbr, void *buffer, +xenidc_buffer_byte_count buffer_byte_count, int out) +{ + xenidc_buffer_byte_count byte_count = min(lbr->byte_count, + buffer_byte_count); + xenidc_buffer_byte_count remainder_offset = 0; + xenidc_buffer_byte_count remainder_count = byte_count; + struct xenidc_lbr top_lbr = *lbr; + trace(); + /* Total amount to copy is the smaller of the two buffers. */ + while (remainder_count != 0) { + /* top_lbr might be virtual so we resolve it to get a */ + /* concrete lbr for the first contiguous chunk of top_lbr. */ + struct xenidc_lbr resolved_lbr = xenidc_lbr_resolve(&top_lbr); + /* resolved_lbr is guaranteed to be concrete so we can look */ + /* its copy method. */ + struct xenidc_lbr_concrete_class *class = + xenidc_lbr_find_concrete_class(resolved_lbr.type); + /* Amount to copy this go may be restricted by the size of */ + /* resolved lbr. */ + xenidc_buffer_byte_count this_go = min(resolved_lbr.byte_count, + remainder_count); + class->copy_in_or_out(class, &resolved_lbr, + (char *)buffer + remainder_offset, this_go, out); + remainder_offset += this_go; + remainder_count -= this_go; + xenidc_lbr_advance(&top_lbr, this_go); + } + return byte_count; +} + +void xenidc_lbr_zero(struct xenidc_lbr *lbr) +{ + struct xenidc_lbr top_lbr = *lbr; + trace(); + while (top_lbr.byte_count != 0) { + /* top_lbr might be virtual so we resolve it to get a */ + /* concrete lbr for the first contiguous chunk of top_lbr. */ + struct xenidc_lbr resolved_lbr = xenidc_lbr_resolve(&top_lbr); + struct xenidc_lbr_concrete_class *class; + class = xenidc_lbr_find_concrete_class(resolved_lbr.type); + class->zero(class, &resolved_lbr); + xenidc_lbr_advance(&top_lbr, resolved_lbr.byte_count); + } +} + +xenidc_buffer_byte_count +xenidc_lbr_copy(struct xenidc_lbr *target, struct xenidc_lbr *source) +{ + xenidc_buffer_byte_count byte_count = min(target->byte_count, + source->byte_count); + struct xenidc_lbr top_target_lbr = *target; + struct xenidc_lbr top_source_lbr = *source; + xenidc_buffer_byte_count remainder_count = byte_count; + trace(); + /* Total amount to copy is the smaller of the two buffers. */ + while (remainder_count != 0) { + struct xenidc_lbr resolved_target_lbr; + struct xenidc_lbr resolved_source_lbr; + xenidc_buffer_byte_count this_go; + struct xenidc_lbr_copy_class *copy_class; + resolved_target_lbr = xenidc_lbr_resolve(&top_target_lbr); + resolved_source_lbr = xenidc_lbr_resolve(&top_source_lbr); + this_go = min(resolved_target_lbr.byte_count, + resolved_source_lbr.byte_count); + copy_class = xenidc_lbr_find_copy_class( + resolved_target_lbr.type, + resolved_source_lbr.type); + if (copy_class != NULL) { + copy_class->copy(copy_class, &resolved_target_lbr, + &resolved_source_lbr, this_go); + } else { + u8 buffer[64]; + struct xenidc_lbr_concrete_class + *target_concrete_class, *source_concrete_class; + struct xenidc_lbr temp_target, temp_source; + xenidc_buffer_byte_count nested_remainder_count; + target_concrete_class = xenidc_lbr_find_concrete_class( + resolved_target_lbr.type); + source_concrete_class = xenidc_lbr_find_concrete_class( + resolved_source_lbr.type); + temp_target = resolved_target_lbr; + temp_source = resolved_source_lbr; + nested_remainder_count = this_go; + do { + xenidc_buffer_byte_count nested_this_go; + nested_this_go = min( + (xenidc_buffer_byte_count)64, + nested_remainder_count); + source_concrete_class->copy_in_or_out( + source_concrete_class, + &temp_source, + buffer, nested_this_go, + 1); + target_concrete_class->copy_in_or_out( + target_concrete_class, + &temp_target, + buffer, nested_this_go, + 0); + xenidc_lbr_advance(&temp_target, + nested_this_go); + xenidc_lbr_advance(&temp_source, + nested_this_go); + nested_remainder_count -= nested_this_go; + } while (nested_remainder_count != 0); + } + xenidc_lbr_advance(&top_target_lbr, this_go); + xenidc_lbr_advance(&top_source_lbr, this_go); + remainder_count -= this_go; + } + return byte_count; +} + +xenidc_buffer_byte_count +xenidc_lbr_virtual_advance(struct xenidc_lbr *lbr, +xenidc_buffer_byte_count byte_count) +{ + xenidc_buffer_byte_count actual_byte_count; + struct xenidc_lbr_virtual_class *class; + trace(); + actual_byte_count = min(lbr->byte_count, byte_count); + class = xenidc_lbr_find_virtual_class(lbr->type); + class->advance(class, lbr, actual_byte_count); + return actual_byte_count; +} + +EXPORT_SYMBOL(xenidc_lbr_register_concrete_class); +EXPORT_SYMBOL(xenidc_lbr_register_copy_class); +EXPORT_SYMBOL(xenidc_lbr_register_virtual_class); +EXPORT_SYMBOL(xenidc_lbr_copy_in_or_out); +EXPORT_SYMBOL(xenidc_lbr_zero); +EXPORT_SYMBOL(xenidc_lbr_copy); +EXPORT_SYMBOL(xenidc_lbr_virtual_advance); diff -r cf3c717101a8 -r a64ebf373f9c linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_remote_buffer_reference.c --- /dev/null Wed Nov 23 15:13:22 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_remote_buffer_reference.c Wed Nov 23 15:38:27 2005 @@ -0,0 +1,130 @@ +/*****************************************************************************/ +/* Xen inter-domain communication remote buffer references */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include "xenidc_trace.h" + +#define XENIDC_RBR_HASH_COUNT 255 +static DEFINE_RWLOCK(xenidc_rbr_lock); +static struct list_head xenidc_rbr_mappable_hash[XENIDC_RBR_HASH_COUNT]; + +static void xenidc_rbr_init(void) +{ + static int initialised = 0; + unsigned long flags; + trace(); + write_lock_irqsave(&xenidc_rbr_lock, flags); + if (!initialised) { + int i; + for (i = 0; i < XENIDC_RBR_HASH_COUNT; i++) { + INIT_LIST_HEAD(&xenidc_rbr_mappable_hash[i]); + } + initialised = 1; + } + write_unlock_irqrestore(&xenidc_rbr_lock, flags); +} + +void +xenidc_rbr_register_buffer_mappable_class( +struct xenidc_rbr_mappable_class *class, xenidc_rbr_type type, +xenidc_rbr_calculate_map_resources_function *calculate_map_resources, +xenidc_rbr_map_function *map, xenidc_rbr_unmap_function *unmap) +{ + int i = (class->type % XENIDC_RBR_HASH_COUNT); + unsigned long flags; + trace(); + xenidc_rbr_init(); + INIT_LIST_HEAD(&class->link); + class->type = type; + class->calculate_map_resources = calculate_map_resources; + class->map = map; + class->unmap = unmap; + write_lock_irqsave(&xenidc_rbr_lock, flags); + list_add_tail(&class->link, &xenidc_rbr_mappable_hash[i]); + write_unlock_irqrestore(&xenidc_rbr_lock, flags); +} + +static inline struct xenidc_rbr_mappable_class * +xenidc_rbr_find_mappable_class(xenidc_rbr_type type) +{ + int i = type % XENIDC_RBR_HASH_COUNT; + struct xenidc_rbr_mappable_class *class; + unsigned long flags; + trace(); + read_lock_irqsave(&xenidc_rbr_lock, flags); + list_for_each_entry(class, &xenidc_rbr_mappable_hash[i], link) { + if (class->type == type) { + read_unlock_irqrestore( + &xenidc_rbr_lock, flags); + return class; + } + } + read_unlock_irqrestore(&xenidc_rbr_lock, flags); + return NULL; +} + +int +xenidc_rbr_calculate_map_resources(struct xenidc_rbr *rbr, +struct xenidc_address *address, struct xenidc_buffer_resource_list *list) +{ + trace(); + if (rbr->byte_count != 0) { + struct xenidc_rbr_mappable_class *class; + class = xenidc_rbr_find_mappable_class(rbr->type); + if (class != NULL) { + return class->calculate_map_resources(class, rbr, + address, list); + } else { + return 1; + } + } else { + *list = xenidc_buffer_resource_list_null(); + return 0; + } +} + +struct xenidc_rbr_mappable_class ** +xenidc_rbr_map(struct xenidc_rbr *rbr, struct xenidc_address *address, +struct xenidc_buffer_resource_provider *provider, void **mapping, +int access_flags) +{ + trace(); + if (rbr->byte_count != 0) { + struct xenidc_rbr_mappable_class *class; + class = xenidc_rbr_find_mappable_class(rbr->type); + return class->map(class, rbr, address, provider, mapping, + access_flags); + } else { + *mapping = NULL; + return (struct xenidc_rbr_mappable_class **)1; + } +} + +void xenidc_rbr_unmap(struct xenidc_rbr_mappable_class **context) +{ + trace(); + if (context != (struct xenidc_rbr_mappable_class **)1) { + (*context)->unmap(context); + } +} diff -r cf3c717101a8 -r a64ebf373f9c linux-2.6-xen-sparse/include/asm-xen/xenidc_address.h --- /dev/null Wed Nov 23 15:13:22 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_address.h Wed Nov 23 15:38:27 2005 @@ -0,0 +1,63 @@ +/*****************************************************************************/ +/* Xen inter-domain communication address. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ +/* */ +/* The xenidc_address type represents an address on the */ +/* interdomain-communication bus. This is useful as an opaque type to pass */ +/* through any layers of code that don't need to be coupled to the */ +/* underlying implementation details of the IDC code. */ + +#ifndef __ASM_XEN_XENIDC_ADDRESS_H__ +#define __ASM_XEN_XENIDC_ADDRESS_H__ + +struct xenidc_address { + const char *local; + const char *remote; + int remote_id; +}; + +static inline void +xenidc_address_init(struct xenidc_address *address, const char *local, +const char *remote, int remote_id) +{ + address->local = local; + address->remote = remote; + address->remote_id = remote_id; +} + +static inline const char * +xenidc_address_query_local_domain(struct xenidc_address *address) +{ + return address->local; +} + +static inline const char * +xenidc_address_query_remote_domain(struct xenidc_address *address) +{ + return address->remote; +} + +static inline int +xenidc_address_query_remote_domain_id(struct xenidc_address *address) +{ + return address->remote_id; +} + +#endif diff -r cf3c717101a8 -r a64ebf373f9c linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h --- /dev/null Wed Nov 23 15:13:22 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h Wed Nov 23 15:38:27 2005 @@ -0,0 +1,358 @@ +/*****************************************************************************/ +/* Xen inter-domain communication local buffer reference object. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ +/* */ +/* Local buffer references are an abstraction for pointers to memory which */ +/* are useful for the following reasons: */ +/* */ +/* They allow clients to describe what type of memory they are passing to a */ +/* service which makes it possible to implement services which deal with */ +/* whatever memory the client happens to have rather than forcing the client */ +/* to implement memory management code to convert to the form required by */ +/* the service. This makes it possible to move memory management code out */ +/* of clients and out of services and into a single core memory management */ +/* implementation. This is good for code quality and maintainability. */ +/* */ +/* They also bundle together the buffer pointer, any start offset (for */ +/* example into a page table) and the buffer length into one convenient */ +/* structure and provide functions for performing all the necessary buffer */ +/* manipulation arithmetic operations. This is convenient for clients and */ +/* good for code quality because the buffer manipulations are easy to use */ +/* and make it less likely for arithmetic errors to lead to buffer overflows.*/ +/* */ +/* They are also useful for implementing logical buffer operations like */ +/* concatenation of buffers and viewing a buffer as a wrapping buffer. */ +/* Again, this is a convenient mechanism which is easier to review and less */ +/* error prone than explicit arithmetic. */ +/* */ +/* This interface provides the basic functions and mechanisms for installing */ +/* different types of local buffer references for referencing different */ +/* kinds of memory, referencing memory in different ways an copying between */ +/* different kinds of memory. */ +/* */ +/* There are three kinds of registration: */ +/* */ +/* A concrete class is used to register a type of memory. For example */ +/* "kernel virtual address space" would be one kind of memory. Another kind */ +/* might for example be shared page cache memory not mapped into the kernel */ +/* virtual address space but for which synchronous access was possible using */ +/* some hypervisor calls. */ +/* */ +/* A virtual class is used to register a way of viewing other local buffers. */ +/* For example, concatenation is a way of looking at two buffers and */ +/* wrapping is a way of looking at a single buffer. */ +/* */ +/* A copy class is used to implement a fast-path mechanism for copying */ +/* between two potentially different types of concrete classes. */ +/* There is an inefficient default mechanism as a fallback but any kinds of */ +/* copying for which performance is a concern should have a bespoke copy */ +/* class. */ + +#ifndef __ASM_XEN_XENIDC_LBR_H__ +#define __ASM_XEN_XENIDC_LBR_H__ + +#include "xenidc_buffer_resource_provider.h" +#include "xenidc_remote_buffer_reference.h" +#include "xenidc_address.h" +#include "xenidc_callback.h" + +/* These flags are private to the implementation but exposed for use in */ +/* inline functions below. */ + +#define XENIDC_LBR_TYPE_FLAG_VIRTUAL 0x80000000 +#define XENIDC_LBR_TYPE_FLAG_VIRTUAL_ADVANCE 0x40000000 + +/* When used, these flags specify what kind of access is _allowed_. */ + +#define XENIDC_LBR_ACCESS_FLAGS_READ 1 +#define XENIDC_LBR_ACCESS_FLAGS_WRITE 2 + +typedef u32 xenidc_lbr_type; + +/* A local buffer reference consists of a type, a type-specific base, a */ +/* byte_offset into the buffer referenced by the base and a byte_count of */ +/* the size of the buffer starting at the byte_offset. */ +/* */ +/* It's OK to copy xenidc_lbr structs and pass them around. They are just a */ +/* convenient way of bundling what would otherwise be four parameters. */ + +struct xenidc_lbr { + xenidc_lbr_type type; + void *base; + xenidc_buffer_byte_count byte_offset; + xenidc_buffer_byte_count byte_count; +}; + +static inline xenidc_buffer_byte_count +xenidc_lbr_query_byte_offset(struct xenidc_lbr *lbr) +{ + return lbr->byte_offset; +} + +static inline xenidc_buffer_byte_count +xenidc_lbr_query_byte_count(struct xenidc_lbr *lbr) +{ + return lbr->byte_count; +} + +struct xenidc_lbr_concrete_class; +struct xenidc_lbr_virtual_class; +struct xenidc_lbr_copy_class; + +typedef void +xenidc_lbr_copy_in_or_out_function(struct xenidc_lbr_concrete_class *class, +struct xenidc_lbr *lbr, void *buffer, xenidc_buffer_byte_count byte_count, +int out); + +typedef void +xenidc_lbr_zero_function(struct xenidc_lbr_concrete_class *class, +struct xenidc_lbr *lbr); + +typedef int +xenidc_lbr_calculate_rbr_resources_function( +struct xenidc_lbr_concrete_class *class, struct xenidc_lbr *lbr, +struct xenidc_address *address, struct xenidc_buffer_resource_list *list); + +typedef struct xenidc_lbr_concrete_class ** +xenidc_lbr_create_rbr_function(struct xenidc_lbr_concrete_class *class, +struct xenidc_lbr *lbr, struct xenidc_address *address, +struct xenidc_buffer_resource_provider *provider, struct xenidc_rbr *rbr, +int access_flags); + +typedef void +xenidc_lbr_revoke_rbr_function(struct xenidc_lbr_concrete_class **context, +struct xenidc_callback *callback); + +typedef void +xenidc_lbr_copy_function(struct xenidc_lbr_copy_class *class, +struct xenidc_lbr *target, struct xenidc_lbr *source, +xenidc_buffer_byte_count byte_count); + +typedef struct xenidc_lbr +xenidc_lbr_resolve_function(struct xenidc_lbr_virtual_class *class, +struct xenidc_lbr *lbr); + +typedef void +xenidc_lbr_advance_function(struct xenidc_lbr_virtual_class *class, +struct xenidc_lbr *lbr, xenidc_buffer_byte_count byte_count); + +/* Concrete class for registering a new type of memory. */ + +struct xenidc_lbr_concrete_class { + struct list_head link; + xenidc_lbr_type type; + xenidc_lbr_copy_in_or_out_function *copy_in_or_out; + xenidc_lbr_zero_function *zero; + xenidc_lbr_calculate_rbr_resources_function *calculate_rbr_resources; + xenidc_lbr_create_rbr_function *create_rbr; + xenidc_lbr_revoke_rbr_function *revoke_rbr; +}; + +/* xenidc_lbr_register_concrete_class returns a xenidc_lbr_type which the */ +/* type implementation must use when creating local buffer references for */ +/* its clients. */ +/* */ +/* The type implementation provides a few methods: */ +/* */ +/* copy_in_or_out is used for copying into the LBR from the kernel virtual */ +/* address space or vice-versa and is used in the fallback mechanism for */ +/* copying between different lbr types by staging the data. */ +/* */ +/* zero is optional and implements a fast zero of the buffer passed in. The */ +/* inefficient default zero operation stages zero bytes into the buffer */ +/* using copy_in_or_out. */ +/* */ +/* The type implementation is required to provide a method to generate a */ +/* remote buffer reference for remote access to the buffer. There is */ +/* currently no default for this though one could be implemented. The */ +/* calculate_rbr_resources function returns a list of resources that would */ +/* be required to create a rbr for the lbr. */ +/* */ +/* create_rbr creates an rbr for the lbr. */ +/* */ +/* revoke_rbr revokes a created rbr. */ + +xenidc_lbr_type +xenidc_lbr_register_concrete_class(struct xenidc_lbr_concrete_class *class, +xenidc_lbr_copy_in_or_out_function *copy_in_or_out, +xenidc_lbr_zero_function *zero, +xenidc_lbr_calculate_rbr_resources_function *calculate_rbr_resources, +xenidc_lbr_create_rbr_function *create_rbr, +xenidc_lbr_revoke_rbr_function *revoke_rbr); + +/* Concrete class for registering a fast-path copy function. */ + +struct xenidc_lbr_copy_class { + struct list_head link; + xenidc_lbr_type target_type; + xenidc_lbr_type source_type; + xenidc_lbr_copy_function *copy; +}; + +/* xenidc_lbr_register_copy_class is used to register a function for */ +/* performing an efficient copy between two types of local buffer references.*/ + +void +xenidc_lbr_register_copy_class(struct xenidc_lbr_copy_class *class, +xenidc_lbr_type target_type, xenidc_lbr_type source_type, +xenidc_lbr_copy_function *copy); + +/* Virtual class for registering a way of viewing local buffers. */ + +struct xenidc_lbr_virtual_class { + struct list_head link; + xenidc_lbr_type type; + xenidc_lbr_resolve_function *resolve; + xenidc_lbr_advance_function *advance; +}; + +/* xenidc_lbr_register_virtual_class is used to register a virtual class for */ +/* a new way of viewing local buffers. */ +/* The type implementation provides a resolve function which takes its type */ +/* of local buffer reference and returns a local buffer reference for an */ +/* underlying buffer type which is the maximal contiguous chunk at the front */ +/* of the reference passed as a parameter. This is generally sufficient to */ +/* implement all the buffer operations. The wrapping type also needs to */ +/* provide a virtual advance function for wrapping the buffer offset. */ + +xenidc_lbr_type +xenidc_lbr_register_virtual_class(struct xenidc_lbr_virtual_class *class, +xenidc_lbr_resolve_function *resolve, +xenidc_lbr_advance_function *advance /* NULL for the efficient default */); + +/* Resolve returns a concrete lbr referencing a contiguous chunk at the head */ +/* of the lbr passed as a parameter. This is used by the implementation of */ +/* the bulk data transfer service. */ + +struct xenidc_lbr xenidc_lbr_resolve(struct xenidc_lbr *lbr); + +/* Calculate RBR resources calculates the resources required to create an */ +/* RBR for the LBR. */ +/* This is used by the implementation of the bulk data transfer service. */ + +int +xenidc_lbr_calculate_rbr_resources(struct xenidc_lbr *lbr, +struct xenidc_address *address, struct xenidc_buffer_resource_list *list); + +/* Create RBR creates a RBR for the LBR by calling the appropriate type */ +/* specific implementation. This is called by the implementation of the */ +/* bulk data transfer services. */ + +struct xenidc_lbr_concrete_class ** +xenidc_lbr_create_rbr(struct xenidc_lbr *lbr, struct xenidc_address *address, +struct xenidc_buffer_resource_provider *provider, struct xenidc_rbr *rbr, +int access_flags); + +/* Revoke RBR revokes a created RBR by calling the appropriate type specific */ +/* implementation. This is called by the implementation of the bulk data */ +/* transfer services. */ + +void +xenidc_lbr_revoke_rbr(struct xenidc_lbr_concrete_class **context, +struct xenidc_callback *callback); + +/* Copy between an lbr and a buffer. Returns the number of bytes copied */ +/* which is the minimum of the source and target byte_counts. */ + +xenidc_buffer_byte_count +xenidc_lbr_copy_in_or_out(struct xenidc_lbr *lbr, void *buffer, +xenidc_buffer_byte_count buffer_byte_count, int out); + +static inline xenidc_buffer_byte_count +xenidc_lbr_copy_out(struct xenidc_lbr *lbr, void *target, +xenidc_buffer_byte_count target_byte_count) +{ + return xenidc_lbr_copy_in_or_out(lbr, target, target_byte_count, 1); +} + +static inline xenidc_buffer_byte_count +xenidc_lbr_copy_in(struct xenidc_lbr *lbr, void *source, +xenidc_buffer_byte_count source_byte_count) +{ + return xenidc_lbr_copy_in_or_out(lbr, source, source_byte_count, 0); +} + +/* Zero a local buffer. */ + +void xenidc_lbr_zero(struct xenidc_lbr *lbr); + +/* Copy between two local buffers. */ + +xenidc_buffer_byte_count +xenidc_lbr_copy(struct xenidc_lbr *target, struct xenidc_lbr *source); + +/* xenidc_lbr_virtual_advance is only exposed for the inline function below. */ +/* Do not call it directly. */ + +xenidc_buffer_byte_count +xenidc_lbr_virtual_advance(struct xenidc_lbr *lbr, +xenidc_buffer_byte_count byte_count); + +/* Advance increments the offset and decrements the length by the amount */ +/* specified which is useful to advance the reference after having copied a */ +/* chunk of data into the start of the buffer. */ +/* Advance returns the remaining length. */ + +static inline xenidc_buffer_byte_count +xenidc_lbr_advance(struct xenidc_lbr *lbr, xenidc_buffer_byte_count byte_count) +{ + if ((lbr->type & XENIDC_LBR_TYPE_FLAG_VIRTUAL_ADVANCE) == 0) { + if (lbr->byte_count > byte_count) { + lbr->byte_offset += byte_count; + lbr->byte_count -= byte_count; + } else { + lbr->byte_offset += lbr->byte_count; + lbr->byte_count = 0; + } + return lbr->byte_count; + } else { + return xenidc_lbr_virtual_advance(lbr, byte_count); + } +} + +/* Truncate reduces the length of the buffer which results in a reference to */ +/* the first byte_count bytes of the buffer (or the whole buffer, whichever */ +/* is less). */ +/* Truncate returns the resulting length of the buffer. */ + +static inline xenidc_buffer_byte_count +xenidc_lbr_truncate(struct xenidc_lbr *lbr, +xenidc_buffer_byte_count byte_count) +{ + if (lbr->byte_count > byte_count) { + lbr->byte_count = byte_count; + } + return lbr->byte_count; +} + +/* Subrange reduces the range of the buffer by advancing the start */ +/* byte_offset bytes and reducing the length to the minimum of byte_count */ +/* and the remaining length. Subrange returns the resulting length of the */ +/* buffer. */ + +static inline xenidc_buffer_byte_count +xenidc_lbr_subrange(struct xenidc_lbr *lbr, +xenidc_buffer_byte_count byte_offset, xenidc_buffer_byte_count byte_count) +{ + (void)xenidc_lbr_advance(lbr, byte_offset); + return xenidc_lbr_truncate(lbr, byte_count); +} + +#endif diff -r cf3c717101a8 -r a64ebf373f9c linux-2.6-xen-sparse/include/asm-xen/xenidc_remote_buffer_reference.h --- /dev/null Wed Nov 23 15:13:22 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_remote_buffer_reference.h Wed Nov 23 15:38:27 2005 @@ -0,0 +1,147 @@ +/*****************************************************************************/ +/* Xen inter-domain communication remote buffer references. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ +/* */ +/* A xenidc_rbr object is sent on the wire between two domains to allow the */ +/* receiving domain to access a buffer belonging to the sending domain. */ +/* */ +/* In general, there may be a number of different kinds of buffers and ways */ +/* of describing them. This interface provides a default 'NULL' */ +/* implementation of remote buffer references (for zero length buffers) and */ +/* a mechanism for installing new types of remote buffer reference for other */ +/* kinds of buffers or buffers described in different ways. */ + +#ifndef __ASM_XEN_XENIDC_RBR_H__ +#define __ASM_XEN_XENIDC_RBR_H__ + +#include +#include +#include +#include "xenidc_address.h" + +typedef u32 xenidc_rbr_type; + +#define XENIDC_RBR_TYPE_NULL 0 + +#define XENIDC_RBR_ACCESS_FLAGS_READ 1 +#define XENIDC_RBR_ACCESS_FLAGS_WRITE 2 + +/* The different types of remote buffer reference must all use the same */ +/* xenidc_rbr structure which provides 32 bytes of space for type-specific */ +/* use. */ + +#define XENIDC_RBR_BASE_BYTE_COUNT 32 + +typedef u32 xenidc_buffer_byte_count; + +struct xenidc_rbr { + xenidc_rbr_type type; + u32 reserved; + struct { + u64 base_space[ XENIDC_RBR_BASE_BYTE_COUNT / 8 ]; + } base; + xenidc_buffer_byte_count byte_offset; + xenidc_buffer_byte_count byte_count; +}; + +/* xenidc_rbr_query_byte_count returns the size of the buffer in bytes. */ + +static inline xenidc_buffer_byte_count +xenidc_rbr_query_byte_count(struct xenidc_rbr *rbr) +{ + return rbr->byte_count; +} + +struct xenidc_rbr_mappable_class; + +typedef int +xenidc_rbr_calculate_map_resources_function( +struct xenidc_rbr_mappable_class *class, struct xenidc_rbr *rbr, +struct xenidc_address *address, struct xenidc_buffer_resource_list *list); + +typedef struct xenidc_rbr_mappable_class ** +xenidc_rbr_map_function(struct xenidc_rbr_mappable_class *class, +struct xenidc_rbr *rbr, struct xenidc_address *address, +struct xenidc_buffer_resource_provider *provider, void **mapping, +int access_flags); + +typedef void +xenidc_rbr_unmap_function(struct xenidc_rbr_mappable_class **context); + +/* If a client might attempt to map a remote buffer reference into the local */ +/* address space (determined by design) then the remote buffer reference */ +/* type implementation must register the methods required to perform the */ +/* mapping. */ + +/* The type implementation must provide a xenidc_rbr_mappable_class. */ + +struct xenidc_rbr_mappable_class { + struct list_head link; + xenidc_rbr_type type; + xenidc_rbr_calculate_map_resources_function *calculate_map_resources; + xenidc_rbr_map_function *map; + xenidc_rbr_unmap_function *unmap; +}; + +/* The type implementation calls the register function with its class */ +/* structure, type, calculate_map_resources, map and unmap functions. */ + +void +xenidc_rbr_register_buffer_mappable_class( +struct xenidc_rbr_mappable_class *class, xenidc_rbr_type type, +xenidc_rbr_calculate_map_resources_function *calculate_map_resources, +xenidc_rbr_map_function *map, xenidc_rbr_unmap_function *unmap); + +/* xenidc_rbr_calculate_map_resources is called to calculate what buffer */ +/* resources would be required to map the rbr into the local address space. */ +/* This is called by the generic code that does mapping on behalf of clients */ +/* and resolves to the type specific implementation. */ + +int xenidc_rbr_calculate_map_resources(struct xenidc_rbr *rbr, +struct xenidc_address *address, struct xenidc_buffer_resource_list *list); + +/* xenidc_rbr_map is called to map a rbr into the local address space. This */ +/* is called by the generic code that does mapping on behalf of the clients */ +/* and resolves to the type specific implementation. */ +/* */ +/* FIXME: This is a synchronous call. A network transparent RBR */ +/* implementation may need to stage the data into a buffer during this call */ +/* so would require this to be an asynchronous call with a callback. Since */ +/* the damage here is contained within the generic code and won't impact the */ +/* drivers we can add this feature later if required. */ + +struct xenidc_rbr_mappable_class ** +xenidc_rbr_map(struct xenidc_rbr *rbr,struct xenidc_address *address, +struct xenidc_buffer_resource_provider *provider, void **mapping, +int access_flags); + +/* xenidc_rbr_unmap is called to unmap an rbr from the local address space. */ +/* This is called by the generic code that does unmapping on behalf of the */ +/* clients and resolves to the type specific implementation. */ +/* */ +/* FIXME: This is a synchronous call. A network transparent RBR */ +/* implementation may need to stage the data from a buffer during this call */ +/* so would require this to be an asynchronous call with a callback. Since */ +/* the damage here is contained within the generic code and won't impact the */ +/* drivers we can add this feature later if required. */ + +void xenidc_rbr_unmap(struct xenidc_rbr_mappable_class **context); + +#endif