/* Multiple-page buffer */ struct hv_multipage_buffer { /* Length and Offset determines the # of pfns in the array */
u32 len;
u32 offset;
u64 pfn_array[MAX_MULTIPAGE_BUFFER_COUNT];
};
/* * Multiple-page buffer array; the pfn array is variable size: * The number of entries in the PFN array is determined by * "len" and "offset".
*/ struct hv_mpb_array { /* Length and Offset determines the # of pfns in the array */
u32 len;
u32 offset;
u64 pfn_array[];
};
struct hv_ring_buffer { /* Offset in bytes from the start of ring data below */
u32 write_index;
/* Offset in bytes from the start of ring data below */
u32 read_index;
u32 interrupt_mask;
/* * WS2012/Win8 and later versions of Hyper-V implement interrupt * driven flow management. The feature bit feat_pending_send_sz * is set by the host on the host->guest ring buffer, and by the * guest on the guest->host ring buffer. * * The meaning of the feature bit is a bit complex in that it has * semantics that apply to both ring buffers. If the guest sets * the feature bit in the guest->host ring buffer, the guest is * telling the host that: * 1) It will set the pending_send_sz field in the guest->host ring * buffer when it is waiting for space to become available, and * 2) It will read the pending_send_sz field in the host->guest * ring buffer and interrupt the host when it frees enough space * * Similarly, if the host sets the feature bit in the host->guest * ring buffer, the host is telling the guest that: * 1) It will set the pending_send_sz field in the host->guest ring * buffer when it is waiting for space to become available, and * 2) It will read the pending_send_sz field in the guest->host * ring buffer and interrupt the guest when it frees enough space * * If either the guest or host does not set the feature bit that it * owns, that guest or host must do polling if it encounters a full * ring buffer, and not signal the other end with an interrupt.
*/
u32 pending_send_sz;
u32 reserved1[12]; union { struct {
u32 feat_pending_send_sz:1;
};
u32 value;
} feature_bits;
/* Pad it to PAGE_SIZE so that data starts on page boundary */
u8 reserved2[PAGE_SIZE - 68];
/* * Ring data starts here + RingDataStartOffset * !!! DO NOT place any fields below this !!!
*/
u8 buffer[];
} __packed;
/* * If the requested ring buffer size is at least 8 times the size of the * header, steal space from the ring buffer for the header. Otherwise, add * space for the header so that is doesn't take too much of the ring buffer * space. * * The factor of 8 is somewhat arbitrary. The goal is to prevent adding a * relatively small header (4 Kbytes on x86) to a large-ish power-of-2 ring * buffer size (such as 128 Kbytes) and so end up making a nearly twice as * large allocation that will be almost half wasted. As a contrasting example, * on ARM64 with 64 Kbyte page size, we don't want to take 64 Kbytes for the * header from a 128 Kbyte allocation, leaving only 64 Kbytes for the ring. * In this latter case, we must add 64 Kbytes for the header and not worry * about what's wasted.
*/ #define VMBUS_HEADER_ADJ(payload_sz) \
((payload_sz) >= 8 * sizeof(struct hv_ring_buffer) ? \
0 : sizeof(struct hv_ring_buffer))
/* Calculate the proper size of a ringbuffer, it must be page-aligned */ #define VMBUS_RING_SIZE(payload_sz) PAGE_ALIGN(VMBUS_HEADER_ADJ(payload_sz) + \
(payload_sz))
struct hv_ring_buffer_info { struct hv_ring_buffer *ring_buffer;
u32 ring_size; /* Include the shared header */ struct reciprocal_value ring_size_div10_reciprocal;
spinlock_t ring_lock;
u32 ring_datasize; /* < ring_size */
u32 priv_read_index; /* * The ring buffer mutex lock. This lock prevents the ring buffer from * being freed while the ring buffer is being accessed.
*/ struct mutex ring_buffer_mutex;
/* Buffer that holds a copy of an incoming host packet */ void *pkt_buffer;
u32 pkt_buffer_size;
};
/* The size of the user defined data buffer for non-pipe offers. */ #define MAX_USER_DEFINED_BYTES 120
/* The size of the user defined data buffer for pipe offers. */ #define MAX_PIPE_USER_DEFINED_BYTES 116
/* * At the center of the Channel Management library is the Channel Offer. This * struct contains the fundamental information about an offer.
*/ struct vmbus_channel_offer {
guid_t if_type;
guid_t if_instance;
/* * These two fields are not currently used.
*/
u64 reserved1;
u64 reserved2;
union { /* Non-pipes: The user has MAX_USER_DEFINED_BYTES bytes. */ struct { unsignedchar user_def[MAX_USER_DEFINED_BYTES];
} std;
/* * Pipes: * The following structure is an integrated pipe protocol, which * is implemented on top of standard user-defined data. Pipe * clients have MAX_PIPE_USER_DEFINED_BYTES left for their own * use.
*/ struct {
u32 pipe_mode; unsignedchar user_def[MAX_PIPE_USER_DEFINED_BYTES];
} pipe;
} u; /* * The sub_channel_index is defined in Win8: a value of zero means a * primary channel and a value of non-zero means a sub-channel. * * Before Win8, the field is reserved, meaning it's always zero.
*/
u16 sub_channel_index;
u16 reserved3;
} __packed;
/* * This structure defines a range in guest physical space that can be made to * look virtually contiguous.
*/ struct gpa_range {
u32 byte_count;
u32 byte_offset;
u64 pfn_array[];
};
/* * This is the format for a GPA-Direct packet, which contains a set of GPA * ranges, in addition to commands and/or data.
*/ struct vmdata_gpa_direct { struct vmpacket_descriptor d;
u32 reserved;
u32 range_cnt; struct gpa_range range[1];
} __packed;
/* Offer Channel parameters */ struct vmbus_channel_offer_channel { struct vmbus_channel_message_header header; struct vmbus_channel_offer offer;
u32 child_relid;
u8 monitorid; /* * win7 and beyond splits this field into a bit field.
*/
u8 monitor_allocated:1;
u8 reserved:7; /* * These are new fields added in win7 and later. * Do not access these fields without checking the * negotiated protocol. * * If "is_dedicated_interrupt" is set, we must not set the * associated bit in the channel bitmap while sending the * interrupt to the host. * * connection_id is to be used in signaling the host.
*/
u16 is_dedicated_interrupt:1;
u16 reserved1:15;
u32 connection_id;
} __packed;
/* * Request Offer -- no parameters, SynIC message contains the partition ID * Set Snoop -- no parameters, SynIC message contains the partition ID * Clear Snoop -- no parameters, SynIC message contains the partition ID * All Offers Delivered -- no parameters, SynIC message contains the partition * ID * Flush Client -- no parameters, SynIC message contains the partition ID
*/
/* Identifies the specific VMBus channel that is being opened. */
u32 child_relid;
/* ID making a particular open request at a channel offer unique. */
u32 openid;
/* GPADL for the channel's ring buffer. */
u32 ringbuffer_gpadlhandle;
/* * Starting with win8, this field will be used to specify * the target virtual processor on which to deliver the interrupt for * the host to guest communication. * Prior to win8, incoming channel interrupts would only * be delivered on cpu 0. Setting this value to 0 would * preserve the earlier behavior.
*/
u32 target_vp;
/* * The upstream ring buffer begins at offset zero in the memory * described by RingBufferGpadlHandle. The downstream ring buffer * follows it at this offset (in pages).
*/
u32 downstream_ringbuffer_pageoffset;
/* User-specific data to be passed along to the server endpoint. */ unsignedchar userdata[MAX_USER_DEFINED_BYTES];
} __packed;
/* Open Channel Result parameters */ struct vmbus_channel_open_result { struct vmbus_channel_message_header header;
u32 child_relid;
u32 openid;
u32 status;
} __packed;
/* * The number of PFNs in a GPADL message is defined by the number of * pages that would be spanned by ByteCount and ByteOffset. If the * implied number of PFNs won't fit in this packet, there will be a * follow-up packet that contains more.
*/ struct vmbus_channel_gpadl_header { struct vmbus_channel_message_header header;
u32 child_relid;
u32 gpadl;
u16 range_buflen;
u16 rangecount; struct gpa_range range[];
} __packed;
/* This is the followup packet that contains more PFNs. */ struct vmbus_channel_gpadl_body { struct vmbus_channel_message_header header;
u32 msgnumber;
u32 gpadl;
u64 pfn[];
} __packed;
/* * On new hosts that support VMBus protocol 5.0, we must use * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message, * and for subsequent messages, we must use the Message Connection ID * field in the host-returned Version Response Message. * * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
*/
u32 msg_conn_id;
} __packed;
/* * Represents each channel msg on the vmbus connection This is a * variable-size data structure depending on the msg type itself
*/ struct vmbus_channel_msginfo { /* Bookkeeping stuff */ struct list_head msglistentry;
/* So far, this is only used to handle gpadl body message */ struct list_head submsglist;
u32 msgsize; /* * The channel message that goes out on the "wire". * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
*/ unsignedchar msg[];
};
/* * Provides request ids for VMBus. Encapsulates guest memory * addresses and stores the next available slot in req_arr * to generate new ids in constant time.
*/ struct vmbus_requestor {
u64 *req_arr; unsignedlong *req_bitmap; /* is a given slot available? */
u32 size;
u64 next_request_id;
spinlock_t req_lock; /* provides atomicity */
};
struct vmbus_device { /* preferred ring buffer size in KB, 0 means no preferred size for this device */
size_t pref_ring_size;
u16 dev_type;
guid_t guid; bool perf_device; bool allowed_in_isolated;
};
struct vmbus_channel_offer_channel offermsg; /* * These are based on the OfferMsg.MonitorId. * Save it here for easy access.
*/
u8 monitor_grp;
u8 monitor_bit;
/* Allocated memory for ring buffer */ struct page *ringbuffer_page;
u32 ringbuffer_pagecount;
u32 ringbuffer_send_offset; struct hv_ring_buffer_info outbound; /* send to parent */ struct hv_ring_buffer_info inbound; /* receive from parent */
struct vmbus_close_msg close_msg;
/* Statistics */
u64 interrupts; /* Host to Guest interrupts */
u64 sig_events; /* Guest to Host events */
/* * Guest to host interrupts caused by the outbound ring buffer changing * from empty to not empty.
*/
u64 intr_out_empty;
/* * Indicates that a full outbound ring buffer was encountered. The flag * is set to true when a full outbound ring buffer is encountered and * set to false when a write to the outbound ring buffer is completed.
*/ bool out_full_flag;
/* * Synchronize channel scheduling and channel removal; see the inline * comments in vmbus_chan_sched() and vmbus_reset_channel_cb().
*/
spinlock_t sched_lock;
/* * A channel can be marked for one of three modes of reading: * BATCHED - callback called from taslket and should read * channel until empty. Interrupts from the host * are masked while read is in process (default). * DIRECT - callback called from tasklet (softirq). * ISR - callback called in interrupt context and must * invoke its own deferred processing. * Host interrupts are disabled and must be re-enabled * when ring is empty.
*/ enum hv_callback_mode {
HV_CALL_BATCHED,
HV_CALL_DIRECT,
HV_CALL_ISR
} callback_mode;
bool is_dedicated_interrupt;
u64 sig_event;
/* * Starting with win8, this field will be used to specify the * target CPU on which to deliver the interrupt for the host * to guest communication. * * Prior to win8, incoming channel interrupts would only be * delivered on CPU 0. Setting this value to 0 would preserve * the earlier behavior.
*/
u32 target_cpu; /* * Support for sub-channels. For high performance devices, * it will be useful to have multiple sub-channels to support * a scalable communication infrastructure with the host. * The support for sub-channels is implemented as an extension * to the current infrastructure. * The initial offer is considered the primary channel and this * offer message will indicate if the host supports sub-channels. * The guest is free to ask for sub-channels to be offered and can * open these sub-channels as a normal "primary" channel. However, * all sub-channels will have the same type and instance guids as the * primary channel. Requests sent on a given channel will result in a * response on the same channel.
*/
/* * Sub-channel creation callback. This callback will be called in * process context when a sub-channel offer is received from the host. * The guest can open the sub-channel in the context of this callback.
*/ void (*sc_creation_callback)(struct vmbus_channel *new_sc);
/* * Channel rescind callback. Some channels (the hvsock ones), need to * register a callback which is invoked in vmbus_onoffer_rescind().
*/ void (*chn_rescind_callback)(struct vmbus_channel *channel);
/* * All Sub-channels of a primary channel are linked here.
*/ struct list_head sc_list; /* * The primary channel this sub-channel belongs to. * This will be NULL for the primary channel.
*/ struct vmbus_channel *primary_channel; /* * Support per-channel state for use by vmbus drivers.
*/ void *per_channel_state;
/* * Defer freeing channel until after all cpu's have * gone through grace period.
*/ struct rcu_head rcu;
/* * For sysfs per-channel properties.
*/ struct kobject kobj;
/* * For performance critical channels (storage, networking * etc,), Hyper-V has a mechanism to enhance the throughput * at the expense of latency: * When the host is to be signaled, we just set a bit in a shared page * and this bit will be inspected by the hypervisor within a certain * window and if the bit is set, the host will be signaled. The window * of time is the monitor latency - currently around 100 usecs. This * mechanism improves throughput by: * * A) Making the host more efficient - each time it wakes up, * potentially it will process more number of packets. The * monitor latency allows a batch to build up. * B) By deferring the hypercall to signal, we will also minimize * the interrupts. * * Clearly, these optimizations improve throughput at the expense of * latency. Furthermore, since the channel is shared for both * control and data messages, control messages currently suffer * unnecessary latency adversely impacting performance and boot * time. To fix this issue, permit tagging the channel as being * in "low latency" mode. In this mode, we will bypass the monitor * mechanism.
*/ bool low_latency;
bool probe_done;
/* * Cache the device ID here for easy access; this is useful, in * particular, in situations where the channel's device_obj has * not been allocated/initialized yet.
*/
u16 device_id;
/* * We must offload the handling of the primary/sub channels * from the single-threaded vmbus_connection.work_queue to * two different workqueue, otherwise we can block * vmbus_connection.work_queue and hang: see vmbus_process_offer().
*/ struct work_struct add_channel_work;
/* * Guest to host interrupts caused by the inbound ring buffer changing * from full to not full while a packet is waiting.
*/
u64 intr_in_full;
/* * The total number of write operations that encountered a full * outbound ring buffer.
*/
u64 out_full_total;
/* * The number of write operations that were the first to encounter a * full outbound ring buffer.
*/
u64 out_full_first;
/* enabling/disabling fuzz testing on the channel (default is false)*/ bool fuzz_testing_state;
/* * Interrupt delay will delay the guest from emptying the ring buffer * for a specific amount of time. The delay is in microseconds and will * be between 1 to a maximum of 1000, its default is 0 (no delay). * The Message delay will delay guest reading on a per message basis * in microseconds between 1 to 1000 with the default being 0 * (no delay).
*/
u32 fuzz_testing_interrupt_delay;
u32 fuzz_testing_message_delay;
/* callback to generate a request ID from a request address */
u64 (*next_request_id_callback)(struct vmbus_channel *channel, u64 rqst_addr); /* callback to retrieve a request address from a request ID */
u64 (*request_addr_callback)(struct vmbus_channel *channel, u64 rqst_id);
/* The max size of a packet on this channel */
u32 max_pkt_size;
/* function to mmap ring buffer memory to the channel's sysfs ring attribute */ int (*mmap_ring_buffer)(struct vmbus_channel *channel, struct vm_area_struct *vma);
/* boolean to control visibility of sysfs for ring buffer */ bool ring_sysfs_visible;
};
#define lock_requestor(channel, flags) \ do { \ struct vmbus_requestor *rqstor = &(channel)->requestor; \
\
spin_lock_irqsave(&rqstor->req_lock, flags); \
} while (0)
/* The format must be the same as struct vmdata_gpa_direct */ struct vmbus_channel_packet_page_buffer {
u16 type;
u16 dataoffset8;
u16 length8;
u16 flags;
u64 transactionid;
u32 reserved;
u32 rangecount; struct hv_page_buffer range[MAX_PAGE_BUFFER_COUNT];
} __packed;
/* The format must be the same as struct vmdata_gpa_direct */ struct vmbus_channel_packet_multipage_buffer {
u16 type;
u16 dataoffset8;
u16 length8;
u16 flags;
u64 transactionid;
u32 reserved;
u32 rangecount; /* Always 1 in this case */ struct hv_multipage_buffer range;
} __packed;
/* The format must be the same as struct vmdata_gpa_direct */ struct vmbus_packet_mpb_array {
u16 type;
u16 dataoffset8;
u16 length8;
u16 flags;
u64 transactionid;
u32 reserved;
u32 rangecount; /* Always 1 in this case */ struct hv_mpb_array range;
} __packed;
/* Base driver object */ struct hv_driver { constchar *name;
/* * A hvsock offer, which has a VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER * channel flag, actually doesn't mean a synthetic device because the * offer's if_type/if_instance can change for every new hvsock * connection. * * However, to facilitate the notification of new-offer/rescind-offer * from vmbus driver to hvsock driver, we can handle hvsock offer as * a special vmbus device, and hence we need the below flag to * indicate if the driver is the hvsock driver or not: we need to * specially treat the hvosck offer & driver in vmbus_match().
*/ bool hvsock;
/* the device type supported by this driver */
guid_t dev_type; conststruct hv_vmbus_device_id *id_table;
int (*suspend)(struct hv_device *); int (*resume)(struct hv_device *);
};
/* Base device object */ struct hv_device { /* the device type id of this device */
guid_t dev_type;
/* the device instance id of this device */
guid_t dev_instance;
u16 vendor_id;
u16 device_id;
struct device device; /* * Driver name to force a match. Do not set directly, because core * frees it. Use driver_set_override() to set or clear it.
*/ constchar *driver_override;
/* * Linux doesn't support these 4 devices: the first two are for * Automatic Virtual Machine Activation, the third is for * Remote Desktop Virtualization, and the fourth is Initial * Machine Configuration (IMC) used only by Windows guests. * {f8e65716-3cb3-4a06-9a60-1889c5cccab5} * {3375baf4-9e15-4b30-b765-67acb10d607b} * {276aacf4-ac15-426c-98dd-7521ad3f01fe} * {c376c1c3-d276-48d2-90a9-c04748072c60}
*/
/* * While we want to handle util services as regular devices, * there is only one instance of each of these services; so * we statically allocate the service specific state.
*/
struct hv_util_service {
u8 *recv_buffer; void *channel; void (*util_cb)(void *); int (*util_init)(struct hv_util_service *); int (*util_init_transport)(void); void (*util_deinit)(void); int (*util_pre_suspend)(void); int (*util_pre_resume)(void);
};
void vmbus_setevent(struct vmbus_channel *channel); /* * Negotiated version with the Host.
*/
extern __u32 vmbus_proto_version;
int vmbus_send_tl_connect_request(const guid_t *shv_guest_servie_id, const guid_t *shv_host_servie_id); int vmbus_send_modifychannel(struct vmbus_channel *channel, u32 target_vp); void vmbus_set_event(struct vmbus_channel *channel); int vmbus_channel_set_cpu(struct vmbus_channel *channel, u32 target_cpu);
/* Get the start of the ring buffer. */ staticinlinevoid *
hv_get_ring_buffer(conststruct hv_ring_buffer_info *ring_info)
{ return ring_info->ring_buffer->buffer;
}
/* make sure mask update is not reordered */
virt_mb();
}
/* * Re-enable host callback and return number of outstanding bytes
*/ staticinline u32 hv_end_read(struct hv_ring_buffer_info *rbi)
{
rbi->ring_buffer->interrupt_mask = 0;
/* make sure mask update is not reordered */
virt_mb();
/* * Now check to see if the ring buffer is still empty. * If it is not, we raced and we need to process new * incoming messages.
*/ return hv_get_bytes_to_read(rbi);
}
/* * An API to support in-place processing of incoming VMBUS packets.
*/
/* Get data payload associated with descriptor */ staticinlinevoid *hv_pkt_data(conststruct vmpacket_descriptor *desc)
{ return (void *)((unsignedlong)desc + (desc->offset8 << 3));
}
/* Get data size associated with descriptor */ staticinline u32 hv_pkt_datalen(conststruct vmpacket_descriptor *desc)
{ return (desc->len8 << 3) - (desc->offset8 << 3);
}
/* Get packet length associated with descriptor */ staticinline u32 hv_pkt_len(conststruct vmpacket_descriptor *desc)
{ return desc->len8 << 3;
}
/* * Interface for passing data between SR-IOV PF and VF drivers. The VF driver * sends requests to read and write blocks. Each block must be 128 bytes or * smaller. Optionally, the VF driver can register a callback function which * will be invoked when the host says that one or more of the first 64 block * IDs is "invalid" which means that the VF driver should reread them.
*/ #define HV_CONFIG_BLOCK_SIZE_MAX 128
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.