summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/include/ipxe/vmbus.h
blob: 26fc578c67f8493b7a2692cf7a948510f27e2908 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
#ifndef _IPXE_VMBUS_H
#define _IPXE_VMBUS_H

/** @file
 *
 * Hyper-V virtual machine bus
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <byteswap.h>
#include <ipxe/uuid.h>
#include <ipxe/device.h>
#include <ipxe/tables.h>
#include <ipxe/uaccess.h>
#include <ipxe/iobuf.h>
#include <ipxe/hyperv.h>

/** VMBus message connection ID */
#define VMBUS_MESSAGE_ID 1

/** VMBus event connection ID */
#define VMBUS_EVENT_ID 2

/** VMBus message type */
#define VMBUS_MESSAGE_TYPE 1

/** VMBus message synthetic interrupt */
#define VMBUS_MESSAGE_SINT 2

/** VMBus version number */
union vmbus_version {
	/** Raw version */
	uint32_t raw;
	/** Major/minor version */
	struct {
		/** Minor version */
		uint16_t minor;
		/** Major version */
		uint16_t major;
	};
} __attribute__ (( packed ));

/** Known VMBus protocol versions */
enum vmbus_raw_version {
	/** Windows Server 2008 */
	VMBUS_VERSION_WS2008 = ( ( 0 << 16 ) | ( 13 << 0 ) ),
	/** Windows 7 */
	VMBUS_VERSION_WIN7 = ( ( 1 << 16 ) | ( 1 << 0 ) ),
	/** Windows 8 */
	VMBUS_VERSION_WIN8 = ( ( 2 << 16 ) | ( 4 << 0 ) ),
	/** Windows 8.1 */
	VMBUS_VERSION_WIN8_1 = ( ( 3 << 16 ) | ( 0 << 0 ) ),
};

/** Guest physical address range descriptor */
struct vmbus_gpa_range {
	/** Byte count */
	uint32_t len;
	/** Starting byte offset */
	uint32_t offset;
	/** Page frame numbers
	 *
	 * The length of this array is implied by the byte count and
	 * starting offset.
	 */
	uint64_t pfn[0];
} __attribute__ (( packed ));

/** VMBus message header */
struct vmbus_message_header {
	/** Message type */
	uint32_t type;
	/** Reserved */
	uint32_t reserved;
} __attribute__ (( packed ));

/** VMBus message types */
enum vmbus_message_type {
	VMBUS_OFFER_CHANNEL = 1,
	VMBUS_REQUEST_OFFERS = 3,
	VMBUS_ALL_OFFERS_DELIVERED = 4,
	VMBUS_OPEN_CHANNEL = 5,
	VMBUS_OPEN_CHANNEL_RESULT = 6,
	VMBUS_CLOSE_CHANNEL = 7,
	VMBUS_GPADL_HEADER = 8,
	VMBUS_GPADL_CREATED = 10,
	VMBUS_GPADL_TEARDOWN = 11,
	VMBUS_GPADL_TORNDOWN = 12,
	VMBUS_INITIATE_CONTACT = 14,
	VMBUS_VERSION_RESPONSE = 15,
	VMBUS_UNLOAD = 16,
	VMBUS_UNLOAD_RESPONSE = 17,
};

/** VMBus "offer channel" message */
struct vmbus_offer_channel {
	/** Message header */
	struct vmbus_message_header header;
	/** Channel type */
	union uuid type;
	/** Channel instance */
	union uuid instance;
	/** Reserved */
	uint8_t reserved_a[16];
	/** Flags */
	uint16_t flags;
	/** Reserved */
	uint8_t reserved_b[2];
	/** User data */
	uint8_t data[120];
	/** Reserved */
	uint8_t reserved_c[4];
	/** Channel ID */
	uint32_t channel;
	/** Monitor ID */
	uint8_t monitor;
	/** Monitor exists */
	uint8_t monitored;
	/** Reserved */
	uint8_t reserved[2];
	/** Connection ID */
	uint32_t connection;
} __attribute__ (( packed ));

/** VMBus "open channel" message */
struct vmbus_open_channel {
	/** Message header */
	struct vmbus_message_header header;
	/** Channel ID */
	uint32_t channel;
	/** Open ID */
	uint32_t id;
	/** Ring buffer GPADL ID */
	uint32_t gpadl;
	/** Reserved */
	uint32_t reserved;
	/** Outbound ring buffer size (in pages) */
	uint32_t out_pages;
	/** User-specific data */
	uint8_t data[120];
} __attribute__ (( packed ));

/** VMBus "open channel result" message */
struct vmbus_open_channel_result {
	/** Message header */
	struct vmbus_message_header header;
	/** Channel ID */
	uint32_t channel;
	/** Open ID */
	uint32_t id;
	/** Status */
	uint32_t status;
} __attribute__ (( packed ));

/** VMBus "close channel" message */
struct vmbus_close_channel {
	/** Message header */
	struct vmbus_message_header header;
	/** Channel ID */
	uint32_t channel;
} __attribute__ (( packed ));

/** VMBus "GPADL header" message */
struct vmbus_gpadl_header {
	/** Message header */
	struct vmbus_message_header header;
	/** Channel ID */
	uint32_t channel;
	/** GPADL ID */
	uint32_t gpadl;
	/** Length of range descriptors */
	uint16_t range_len;
	/** Number of range descriptors */
	uint16_t range_count;
	/** Range descriptors */
	struct vmbus_gpa_range range[0];
} __attribute__ (( packed ));

/** VMBus "GPADL created" message */
struct vmbus_gpadl_created {
	/** Message header */
	struct vmbus_message_header header;
	/** Channel ID */
	uint32_t channel;
	/** GPADL ID */
	uint32_t gpadl;
	/** Creation status */
	uint32_t status;
} __attribute__ (( packed ));

/** VMBus "GPADL teardown" message */
struct vmbus_gpadl_teardown {
	/** Message header */
	struct vmbus_message_header header;
	/** Channel ID */
	uint32_t channel;
	/** GPADL ID */
	uint32_t gpadl;
} __attribute__ (( packed ));

/** VMBus "GPADL torndown" message */
struct vmbus_gpadl_torndown {
	/** Message header */
	struct vmbus_message_header header;
	/** GPADL ID */
	uint32_t gpadl;
} __attribute__ (( packed ));

/** VMBus "initiate contact" message */
struct vmbus_initiate_contact {
	/** Message header */
	struct vmbus_message_header header;
	/** Requested version */
	union vmbus_version version;
	/** Target virtual CPU */
	uint32_t vcpu;
	/** Interrupt page base address */
	uint64_t intr;
	/** Parent to child monitor page base address */
	uint64_t monitor_in;
	/** Child to parent monitor page base address */
	uint64_t monitor_out;
} __attribute__ (( packed ));

/** VMBus "version response" message */
struct vmbus_version_response {
	/** Message header */
	struct vmbus_message_header header;
	/** Version is supported */
	uint8_t supported;
	/** Reserved */
	uint8_t reserved[3];
	/** Version */
	union vmbus_version version;
} __attribute__ (( packed ));

/** VMBus message */
union vmbus_message {
	/** Common message header */
	struct vmbus_message_header header;
	/** "Offer channel" message */
	struct vmbus_offer_channel offer;
	/** "Open channel" message */
	struct vmbus_open_channel open;
	/** "Open channel result" message */
	struct vmbus_open_channel_result opened;
	/** "Close channel" message */
	struct vmbus_close_channel close;
	/** "GPADL header" message */
	struct vmbus_gpadl_header gpadlhdr;
	/** "GPADL created" message */
	struct vmbus_gpadl_created created;
	/** "GPADL teardown" message */
	struct vmbus_gpadl_teardown teardown;
	/** "GPADL torndown" message */
	struct vmbus_gpadl_torndown torndown;
	/** "Initiate contact" message */
	struct vmbus_initiate_contact initiate;
	/** "Version response" message */
	struct vmbus_version_response version;
};

/** VMBus packet header */
struct vmbus_packet_header {
	/** Type */
	uint16_t type;
	/** Length of packet header (in quadwords) */
	uint16_t hdr_qlen;
	/** Length of packet (in quadwords) */
	uint16_t qlen;
	/** Flags */
	uint16_t flags;
	/** Transaction ID
	 *
	 * This is an opaque token: we therefore treat it as
	 * native-endian and don't worry about byte-swapping.
	 */
	uint64_t xid;
} __attribute__ (( packed ));

/** VMBus packet types */
enum vmbus_packet_type {
	VMBUS_DATA_INBAND = 6,
	VMBUS_DATA_XFER_PAGES = 7,
	VMBUS_DATA_GPA_DIRECT = 9,
	VMBUS_CANCELLATION = 10,
	VMBUS_COMPLETION = 11,
};

/** VMBus packet flags */
enum vmbus_packet_flags {
	VMBUS_COMPLETION_REQUESTED = 0x0001,
};

/** VMBus GPA direct header */
struct vmbus_gpa_direct_header {
	/** Packet header */
	struct vmbus_packet_header header;
	/** Reserved */
	uint32_t reserved;
	/** Number of range descriptors */
	uint32_t range_count;
	/** Range descriptors */
	struct vmbus_gpa_range range[0];
} __attribute__ (( packed ));

/** VMBus transfer page range */
struct vmbus_xfer_page_range {
	/** Length */
	uint32_t len;
	/** Offset */
	uint32_t offset;
} __attribute__ (( packed ));

/** VMBus transfer page header */
struct vmbus_xfer_page_header {
	/** Packet header */
	struct vmbus_packet_header header;
	/** Page set ID */
	uint16_t pageset;
	/** Sender owns page set */
	uint8_t owner;
	/** Reserved */
	uint8_t reserved;
	/** Number of range descriptors */
	uint32_t range_count;
	/** Range descriptors */
	struct vmbus_xfer_page_range range[0];
} __attribute__ (( packed ));

/** Maximum expected size of VMBus packet header */
#define VMBUS_PACKET_MAX_HEADER_LEN 64

/** VMBus maximum-sized packet header */
union vmbus_packet_header_max {
	/** Common header */
	struct vmbus_packet_header header;
	/** GPA direct header */
	struct vmbus_gpa_direct_header gpa;
	/** Transfer page header */
	struct vmbus_xfer_page_header xfer;
	/** Padding to maximum supported size */
	uint8_t padding[VMBUS_PACKET_MAX_HEADER_LEN];
} __attribute__ (( packed ));

/** VMBus packet footer */
struct vmbus_packet_footer {
	/** Reserved */
	uint32_t reserved;
	/** Producer index of the first byte of the packet */
	uint32_t prod;
} __attribute__ (( packed ));

/** VMBus ring buffer
 *
 * This is the structure of the each of the ring buffers created when
 * a VMBus channel is opened.
 */
struct vmbus_ring {
	/** Producer index (modulo ring length) */
	uint32_t prod;
	/** Consumer index (modulo ring length) */
	uint32_t cons;
	/** Interrupt mask */
	uint32_t intr_mask;
	/** Reserved */
	uint8_t reserved[4084];
	/** Ring buffer contents */
	uint8_t data[0];
} __attribute__ (( packed ));

/** VMBus interrupt page */
struct vmbus_interrupt {
	/** Inbound interrupts */
	uint8_t in[ PAGE_SIZE / 2 ];
	/** Outbound interrupts */
	uint8_t out[ PAGE_SIZE / 2 ];
} __attribute__ (( packed ));

/** A virtual machine bus */
struct vmbus {
	/** Interrupt page */
	struct vmbus_interrupt *intr;
	/** Inbound notifications */
	struct hv_monitor *monitor_in;
	/** Outbound notifications */
	struct hv_monitor *monitor_out;
	/** Received message buffer */
	const union vmbus_message *message;
};

struct vmbus_device;

/** VMBus channel operations */
struct vmbus_channel_operations {
	/**
	 * Handle received control packet
	 *
	 * @v vmdev		VMBus device
	 * @v xid		Transaction ID
	 * @v data		Data
	 * @v len		Length of data
	 * @ret rc		Return status code
	 */
	int ( * recv_control ) ( struct vmbus_device *vmdev, uint64_t xid,
				 const void *data, size_t len );
	/**
	 * Handle received data packet
	 *
	 * @v vmdev		VMBus device
	 * @v xid		Transaction ID
	 * @v data		Data
	 * @v len		Length of data
	 * @v list		List of I/O buffers
	 * @ret rc		Return status code
	 *
	 * This function takes ownership of the I/O buffer.  It should
	 * eventually call vmbus_send_completion() to indicate to the
	 * host that the buffer can be reused.
	 */
	int ( * recv_data ) ( struct vmbus_device *vmdev, uint64_t xid,
			      const void *data, size_t len,
			      struct list_head *list );
	/**
	 * Handle received completion packet
	 *
	 * @v vmdev		VMBus device
	 * @v xid		Transaction ID
	 * @v data		Data
	 * @v len		Length of data
	 * @ret rc		Return status code
	 */
	int ( * recv_completion ) ( struct vmbus_device *vmdev, uint64_t xid,
				    const void *data, size_t len );
	/**
	 * Handle received cancellation packet
	 *
	 * @v vmdev		VMBus device
	 * @v xid		Transaction ID
	 * @ret rc		Return status code
	 */
	int ( * recv_cancellation ) ( struct vmbus_device *vmdev,
				      uint64_t xid );
};

struct vmbus_xfer_pages;

/** VMBus transfer page set operations */
struct vmbus_xfer_pages_operations {
	/**
	 * Copy data from transfer page
	 *
	 * @v pages		Transfer page set
	 * @v data		Data buffer
	 * @v offset		Offset within page set
	 * @v len		Length within page set
	 * @ret rc		Return status code
	 */
	int ( * copy ) ( struct vmbus_xfer_pages *pages, void *data,
			 size_t offset, size_t len );
};

/** VMBus transfer page set */
struct vmbus_xfer_pages {
	/** List of all transfer page sets */
	struct list_head list;
	/** Page set ID (in protocol byte order) */
	uint16_t pageset;
	/** Page set operations */
	struct vmbus_xfer_pages_operations *op;
};

/** A VMBus device */
struct vmbus_device {
	/** Generic iPXE device */
	struct device dev;
	/** Hyper-V hypervisor */
	struct hv_hypervisor *hv;

	/** Channel ID */
	unsigned int channel;
	/** Monitor ID */
	unsigned int monitor;
	/** Signal channel
	 *
	 * @v vmdev		VMBus device
	 */
	void ( * signal ) ( struct vmbus_device *vmdev );

	/** Outbound ring buffer length */
	uint32_t out_len;
	/** Inbound ring buffer length */
	uint32_t in_len;
	/** Outbound ring buffer */
	struct vmbus_ring *out;
	/** Inbound ring buffer */
	struct vmbus_ring *in;
	/** Ring buffer GPADL ID */
	unsigned int gpadl;

	/** Channel operations */
	struct vmbus_channel_operations *op;
	/** Maximum expected data packet length */
	size_t mtu;
	/** Packet buffer */
	void *packet;
	/** List of transfer page sets */
	struct list_head pages;

	/** Driver */
	struct vmbus_driver *driver;
	/** Driver-private data */
	void *priv;
};

/** A VMBus device driver */
struct vmbus_driver {
	/** Name */
	const char *name;
	/** Device type */
	union uuid type;
	/** Probe device
	 *
	 * @v vmdev		VMBus device
	 * @ret rc		Return status code
	 */
	int ( * probe ) ( struct vmbus_device *vmdev );
	/** Remove device
	 *
	 * @v vmdev		VMBus device
	 */
	void ( * remove ) ( struct vmbus_device *vmdev );
};

/** VMBus device driver table */
#define VMBUS_DRIVERS __table ( struct vmbus_driver, "vmbus_drivers" )

/** Declare a VMBus device driver */
#define __vmbus_driver __table_entry ( VMBUS_DRIVERS, 01 )

/**
 * Set VMBus device driver-private data
 *
 * @v vmdev		VMBus device
 * @v priv		Private data
 */
static inline void vmbus_set_drvdata ( struct vmbus_device *vmdev, void *priv ){
	vmdev->priv = priv;
}

/**
 * Get VMBus device driver-private data
 *
 * @v vmdev		VMBus device
 * @ret priv		Private data
 */
static inline void * vmbus_get_drvdata ( struct vmbus_device *vmdev ) {
	return vmdev->priv;
}

/** Construct VMBus type */
#define VMBUS_TYPE( a, b, c, d, e0, e1, e2, e3, e4, e5 ) {		\
	.canonical = {							\
		cpu_to_le32 ( a ), cpu_to_le16 ( b ),			\
		cpu_to_le16 ( c ), cpu_to_be16 ( d ),			\
		{ e0, e1, e2, e3, e4, e5 }				\
	 } }

/**
 * Check if data is present in ring buffer
 *
 * @v vmdev		VMBus device
 * @v has_data		Data is present
 */
static inline __attribute__ (( always_inline )) int
vmbus_has_data ( struct vmbus_device *vmdev ) {

	return ( vmdev->in->prod != vmdev->in->cons );
}

/**
 * Register transfer page set
 *
 * @v vmdev		VMBus device
 * @v pages		Transfer page set
 * @ret rc		Return status code
 */
static inline __attribute__ (( always_inline )) int
vmbus_register_pages ( struct vmbus_device *vmdev,
		       struct vmbus_xfer_pages *pages ) {

	list_add ( &pages->list, &vmdev->pages );
	return 0;
}

/**
 * Unregister transfer page set
 *
 * @v vmdev		VMBus device
 * @v pages		Transfer page set
 */
static inline __attribute__ (( always_inline )) void
vmbus_unregister_pages ( struct vmbus_device *vmdev,
			 struct vmbus_xfer_pages *pages ) {

	list_check_contains_entry ( pages, &vmdev->pages, list );
	list_del ( &pages->list );
}

extern int vmbus_establish_gpadl ( struct vmbus_device *vmdev, userptr_t data,
				   size_t len );
extern int vmbus_gpadl_teardown ( struct vmbus_device *vmdev,
				  unsigned int gpadl );
extern int vmbus_open ( struct vmbus_device *vmdev,
			struct vmbus_channel_operations *op,
			size_t out_len, size_t in_len, size_t mtu );
extern void vmbus_close ( struct vmbus_device *vmdev );
extern int vmbus_send_control ( struct vmbus_device *vmdev, uint64_t xid,
				const void *data, size_t len );
extern int vmbus_send_data ( struct vmbus_device *vmdev, uint64_t xid,
			     const void *data, size_t len,
			     struct io_buffer *iobuf );
extern int vmbus_send_completion ( struct vmbus_device *vmdev, uint64_t xid,
				   const void *data, size_t len );
extern int vmbus_send_cancellation ( struct vmbus_device *vmdev, uint64_t xid );
extern int vmbus_poll ( struct vmbus_device *vmdev );
extern void vmbus_dump_channel ( struct vmbus_device *vmdev );

extern int vmbus_probe ( struct hv_hypervisor *hv, struct device *parent );
extern void vmbus_remove ( struct hv_hypervisor *hv, struct device *parent );

#endif /* _IPXE_VMBUS_H */