summary refs log tree commit diff
path: root/crosvm_plugin/crosvm.h
blob: c7589e29ad565acf89e80f3d258a1976c377d334 (plain) (blame)
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
/*
 * Copyright 2017 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef __CROSVM_H__
#define __CROSVM_H__

#include <assert.h>
#include <stdint.h>
#include <stdbool.h>

#include <linux/kvm.h>

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * This module is used to implement a plugin for crosvm.
 *
 * A plugin for crosvm interfaces with the virtual machine using the `struct
 * crosvm` object and its child objects. A typical plugin is expected to call
 * `crosvm_connect`, perform some amount of setup with the functions defined
 * here, get a handle to every vcpu using `struct crosvm_vcpu` and then call
 * `crosvm_start`. Each vcpu will then be waited on with `crosvm_vcpu_wait`,
 * each event will be responded to by the plugin, and then the vcpu is resumed
 * with `crosvm_vcpu_resume`. The vcpu state can only be examined and modified
 * between the `crosvm_vcpu_wait` and `crosvm_vcpu_resume` calls. The crosvm
 * connection can be used to modify global virtual machine state at any time,
 * with some structural restrictions after `crosvm_start` is called.
 *
 * In general, functions that return an `int` return 0 on success or a non-
 * negative file descriptor if one is expected. A negative return value is an
 * errno and indicates error. Functions that take a pointer-to-pointer to an
 * opaque structure either return a structure or delete and nullify that
 * structure pointer.
 */

/*
 * We use Semantic Versioning (http://semver.org/) here, which means that as
 * long as MAJOR is 0, breaking changes can occur, but once MAJOR is non-zero, a
 * breaking change requires a MAJOR version bump. The MINOR number increases as
 * backward compatible functionality is added. The PATCH number increases bug
 * fixes are done. The version numbers indicate here are for the plugin API and
 * do not indicate anything about what version of crosvm is running.
 */
#define CROSVM_API_MAJOR 0
#define CROSVM_API_MINOR 13
#define CROSVM_API_PATCH 0

enum crosvm_address_space {
  /* I/O port */
  CROSVM_ADDRESS_SPACE_IOPORT = 0,
  /* physical memory space */
  CROSVM_ADDRESS_SPACE_MMIO,
};

/* Handle to the parent crosvm process. */
struct crosvm;

/* Handle to a register ioeventfd. */
struct crosvm_io;

/* Handle to a registered range of shared memory. */
struct crosvm_memory;

/* Handle to a registered irqfd. */
struct crosvm_irq;

/* Handle to one of the VM's VCPUs. */
struct crosvm_vcpu;

/*
 * Connects to the parent crosvm process and returns a new `struct crosvm`
 * interface object.
 *
 * This is the entry point for interfacing with crosvm as a plugin. This should
 * be called before any other function. The returned object is not-thread safe.
 */
int crosvm_connect(struct crosvm**);

/*
 * Creates another connection for interfacing with crosvm concurrently.
 *
 * The new connection behaves exactly like the original `struct crosvm` but can
 * be used concurrently on a different thread than the original. Actual
 * execution order of the requests to crosvm is unspecified but every request is
 * completed when the `crosvm_*` call returns.
 *
 * It is invalid to call this after `crosvm_start` is called on any `struct
 * crosvm`.
 */
int crosvm_new_connection(struct crosvm*, struct crosvm**);

/*
 * Destroys this connection and tells the parent crosvm process to stop
 * listening for messages from it.
 */
int crosvm_destroy_connection(struct crosvm**);

/*
 * Gets an eventfd that is triggered when this plugin should exit.
 *
 * The returned eventfd is owned by the caller but the underlying event is
 * shared and will therefore only trigger once.
 */
int crosvm_get_shutdown_eventfd(struct crosvm*);

/*
 * Gets a bool indicating if a KVM_CAP_* enum is supported on this VM
 */
int crosvm_check_extension(struct crosvm*, uint32_t __extension,
                           bool *__has_extension);

/*
 * Queries x86 cpuid features which are supported by the hardware and
 * kvm.
 */
int crosvm_get_supported_cpuid(struct crosvm*, uint32_t __entry_count,
                               struct kvm_cpuid_entry2 *__cpuid_entries,
                               uint32_t *__out_count);

/*
 * Queries x86 cpuid features which are emulated by kvm.
 */
int crosvm_get_emulated_cpuid(struct crosvm*, uint32_t __entry_count,
                              struct kvm_cpuid_entry2 *__cpuid_entries,
                              uint32_t *__out_count);

/*
 * The network configuration for a crosvm instance.
 */
struct crosvm_net_config {
  /*
   * The tap device fd. This fd is owned by the caller, and should be closed
   * by the caller when it is no longer in use.
   */
  int tap_fd;
  /* The IPv4 address of the tap interface, in network (big-endian) format. */
  uint32_t host_ip;
  /* The netmask of the tap interface subnet, in network (big-endian) format. */
  uint32_t netmask;
  /* The mac address of the host side of the tap interface. */
  uint8_t host_mac_address[6];
  uint8_t _padding[2];
};

#ifdef static_assert
static_assert(sizeof(struct crosvm_net_config) == 20,
              "extra padding in struct crosvm_net_config");
#endif

/*
 * Gets the network configuration.
 */
int crosvm_net_get_config(struct crosvm*, struct crosvm_net_config*);

/*
 * Registers a range in the given address space that, when accessed, will block
 * and wait for a crosvm_vcpu_resume call.
 *
 * To unreserve a range previously reserved by this function, pass the |__space|
 * and |__start| of the old reservation with a 0 |__length|.
 */
int crosvm_reserve_range(struct crosvm*, uint32_t __space, uint64_t __start,
                         uint64_t __length);

/*
 * Sets the state of the given irq pin.
 */
int crosvm_set_irq(struct crosvm*, uint32_t __irq_id, bool __active);

enum crosvm_irq_route_kind {
  /* IRQ pin to GSI route */
  CROSVM_IRQ_ROUTE_IRQCHIP = 0,
  /* MSI address and data to GSI route */
  CROSVM_IRQ_ROUTE_MSI,
};

/* One entry in the array of irq routing table */
struct crosvm_irq_route {
  /* The IRQ number to trigger. */
  uint32_t irq_id;
  /* A `crosvm_irq_route_kind` indicating which union member to use */
  uint32_t kind;
  union {
    struct {
      /*
       * One of KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE, or
       * KVM_IRQCHIP_IOAPIC indicating which irqchip the indicated pin is on.
       */
      uint32_t irqchip;
      /* The pin on the irqchip used to trigger the IRQ. */
      uint32_t pin;
    } irqchip;

    struct {
      /* Address that triggers the irq. */
      uint64_t address;
      /* Data written to `address` that triggers the irq */
      uint32_t data;

      uint8_t _reserved[4];
    } msi;

    uint8_t _reserved[16];
  };
};

#ifdef static_assert
static_assert(sizeof(struct crosvm_irq_route) == 24,
              "extra padding in struct crosvm_irq_route");
#endif

/*
 * Sets all the gsi routing entries to those indicated by `routes`.
 *
 * To remove all routing entries, pass NULL for `routes` and 0 to route_count.
 */
int crosvm_set_irq_routing(struct crosvm*, uint32_t __route_count,
                           const struct crosvm_irq_route* __routes);

/* Gets the state of interrupt controller in a VM. */
int crosvm_get_pic_state(struct crosvm *, bool __primary,
                         struct kvm_pic_state *__pic_state);

/* Sets the state of interrupt controller in a VM. */
int crosvm_set_pic_state(struct crosvm *, bool __primary,
                         struct kvm_pic_state *__pic_state);

/* Gets the state of IOAPIC in a VM. */
int crosvm_get_ioapic_state(struct crosvm *,
                            struct kvm_ioapic_state *__ioapic_state);

/* Sets the state of IOAPIC in a VM. */
int crosvm_set_ioapic_state(struct crosvm *,
                            struct kvm_ioapic_state *__ioapic_state);

/* Gets the state of interrupt controller in a VM. */
int crosvm_get_pit_state(struct crosvm *, struct kvm_pit_state2 *__pit_state);

/* Sets the state of interrupt controller in a VM. */
int crosvm_set_pit_state(struct crosvm *,
                         const struct kvm_pit_state2 *__pit_state);

/* Sets the identity map address as in the KVM_SET_IDENTITY_MAP_ADDR ioctl. */
int crosvm_set_identity_map_addr(struct crosvm*, uint32_t __addr);

/*
 * Triggers a CROSVM_VCPU_EVENT_KIND_PAUSED event on each vcpu identified
 * |__cpu_mask|.
 *
 * The `user` pointer will be given as the `user` pointer in the `struct
 * crosvm_vcpu_event` returned by crosvm_vcpu_wait.
 */
int crosvm_pause_vcpus(struct crosvm*, uint64_t __cpu_mask, void* __user);

/*
 * Call once initialization is done. This indicates that crosvm should proceed
 * with running the VM.
 *
 * After this call, this function is no longer valid to call.
 */
int crosvm_start(struct crosvm*);

/*
 * Registers an eventfd that is triggered asynchronously on write in |__space|
 * at the given |__addr|.
 *
 * If |__datamatch| is non-NULL, it must be contain |__length| bytes that will
 * be compared to the bytes being written by the vcpu which will only trigger
 * the eventfd if equal. If datamatch is NULL all writes to the address will
 * trigger the eventfd.
 *
 * On successful registration, returns a non-negative eventfd owned by the
 * caller.
 */
int crosvm_create_io_event(struct crosvm*, uint32_t __space, uint64_t __addr,
                           uint32_t __len, const uint8_t* __datamatch,
                           struct crosvm_io**);

/*
 * Destroys the given io event and unregisters it from the VM.
 */
int crosvm_destroy_io_event(struct crosvm*, struct crosvm_io**);

/*
 * Gets the eventfd triggered by the given io event.
 *
 * The returned fd is owned by the given `struct crosvm_io` and has a lifetime
 * equal to that handle.
 */
int crosvm_io_event_fd(struct crosvm_io*);

/*
 * Creates a shared memory segment backed by a memfd.
 *
 * Inserts non-overlapping memory pages in the guest physical address range
 * specified by |__start| address and |__length| bytes. The memory pages are
 * backed by the memfd |__fd| and are taken starting at |__offset| bytes from
 * the beginning of the memfd.
 *
 * The `memfd_create` syscall |__fd| must be used to create |__fd| and a shrink
 * seal must have been added to |__fd|. The memfd must be at least
 * `__length+__offset` bytes long.
 *
 * If |read_only| is true, attempts by the guest to write to this memory region
 * will trigger an IO access exit.
 *
 * To use the `crosvm_memory_get_dirty_log` method with the returned object,
 * |__dirty_log| must be true.
 */
int crosvm_create_memory(struct crosvm*, int __fd, uint64_t __offset,
                         uint64_t __length, uint64_t __start,
                         bool __read_only, bool __dirty_log,
                         struct crosvm_memory**);

/*
 * Destroys the given shared memory and unregisters it from guest physical
 * address space.
 */
int crosvm_destroy_memory(struct crosvm*, struct crosvm_memory**);

/*
 * For a given memory region returns a bitmap containing any pages
 * dirtied since the last call to this function.
 *
 * The `log` array must have as many bits as the memory segment has pages.
 */
int crosvm_memory_get_dirty_log(struct crosvm*, struct crosvm_memory*,
                                uint8_t* __log);

/*
 * Creates an irq eventfd that can be used to trigger an irq asynchronously.
 *
 * The irq that will be triggered is identified as pin |__irq_id|.
 */
int crosvm_create_irq_event(struct crosvm*, uint32_t __irq_id,
                            struct crosvm_irq**);

/*
 * Unregisters and destroys an irq eventfd.
 */
int crosvm_destroy_irq_event(struct crosvm*, struct crosvm_irq**);

/*
 * Gets the eventfd used to trigger the irq
 *
 * The returned fd is owned by the given `struct crosvm_irq` and has a lifetime
 * equal to that handle.
 */
int crosvm_irq_event_get_fd(const struct crosvm_irq*);

/*
 * Gets the resample eventfd associated with the crosvm_irq object.
 */
int crosvm_irq_event_get_resample_fd(const struct crosvm_irq*);

enum crosvm_vcpu_event_kind {
  /*
   * The first event returned by crosvm_vcpu_wait, indicating the VCPU has been
   * created but not yet started for the first time.
   */
  CROSVM_VCPU_EVENT_KIND_INIT = 0,

  /*
   * Access to an address in a space previously reserved by
   * crosvm_reserve_range.
   */
  CROSVM_VCPU_EVENT_KIND_IO_ACCESS,

  /*
   * A pause on this vcpu (and possibly others) was requested by this plugin in
   * a `crosvm_pause_vcpus` call.
   */
  CROSVM_VCPU_EVENT_KIND_PAUSED,
};

struct crosvm_vcpu_event {
  /* Indicates the kind of event and which union member is valid. */
  uint32_t kind;

  uint8_t _padding[4];

  union {
    /* CROSVM_VCPU_EVENT_KIND_IO_ACCESS */
    struct {
      /*
       * One of `enum crosvm_address_space` indicating which address space the
       * access occurred in.
       */
      uint32_t address_space;

      uint8_t _padding[4];

      /* The address that the access occurred at. */
      uint64_t address;

      /*
       * In the case that `is_write` is true, the first `length` bytes are the
       * data being written by the vcpu.
       */
      uint8_t *data;

      /*
       * Number of bytes in the access. In the case that the access is larger
       * than 8 bytes, such as by AVX-512 instructions, multiple vcpu access
       * events are generated serially to cover each 8 byte fragment of the
       * access.
       */
      uint32_t length;

      /*
       * True if the vcpu was attempting to write, false in case of an attempt
       * to read.
       */
      uint8_t is_write;

      uint8_t _reserved[3];
    } io_access;

    /* CROSVM_VCPU_EVENT_KIND_USER */
    void *user;

    uint8_t _reserved[64];
  };
};

#ifdef static_assert
static_assert(sizeof(struct crosvm_vcpu_event) == 72,
              "extra padding in struct crosvm_vcpu_event");
#endif

/*
 * Gets the vcpu object for the given |__cpu_id|.
 *
 *
 * The `struct crosvm_vcpu` is owned by `struct crosvm`. Each call with the same
 * `crosvm` and |__cpu_id| will yield the same pointer. The `crosvm_vcpu` does
 * not need to be destroyed or created explicitly.
 *
 * The range of valid |__cpu_id|s is 0 to the number of vcpus - 1. To get every
 * `crosvm_vcpu`, simply call this function iteratively with increasing
 * |__cpu_id| until `-ENOENT` is returned.
 *
 */
int crosvm_get_vcpu(struct crosvm*, uint32_t __cpu_id, struct crosvm_vcpu**);

/*
 * Blocks until a vcpu event happens that requires a response.
 *
 * When crosvm_vcpu_wait returns successfully, the event structure is filled
 * with the description of the event that occurred. The vcpu will suspend
 * execution until a matching call to `crosvm_vcpu_resume` is made. Until such a
 * call is made, the vcpu's run structure can be read and written using any
 * `crosvm_vcpu_get` or `crosvm_vcpu_set` function.
 */
int crosvm_vcpu_wait(struct crosvm_vcpu*, struct crosvm_vcpu_event*);

/*
 * Resumes execution of a vcpu after a call to `crosvm_vcpu_wait` returns.
 *
 * In the case that the event was a read operation, `data` indicates what the
 * result of that read operation should be. If the read operation was larger
 * than 8 bytes, such as by AVX-512 instructions, this will not actually resume
 * the vcpu, but instead generate another vcpu access event of the next fragment
 * of the read, which can be handled by the next `crosvm_vcpu_wait` call.
 *
 * Once the vcpu event has been responded to sufficiently enough to resume
 * execution, `crosvm_vcpu_resume` should be called. After `crosvm_vcpu_resume`
 * is called, none of the vcpu state operations are valid until the next time
 * `crosvm_vcpu_wait` returns.
 */
int crosvm_vcpu_resume(struct crosvm_vcpu*);

/* Gets the state of the vcpu's registers. */
int crosvm_vcpu_get_regs(struct crosvm_vcpu*, struct kvm_regs*);
/* Sets the state of the vcpu's registers. */
int crosvm_vcpu_set_regs(struct crosvm_vcpu*, const struct kvm_regs*);

/* Gets the state of the vcpu's special registers. */
int crosvm_vcpu_get_sregs(struct crosvm_vcpu*, struct kvm_sregs*);
/* Sets the state of the vcpu's special registers. */
int crosvm_vcpu_set_sregs(struct crosvm_vcpu*, const struct kvm_sregs*);

/* Gets the state of the vcpu's floating point unint. */
int crosvm_vcpu_get_fpu(struct crosvm_vcpu*, struct kvm_fpu*);
/* Sets the state of the vcpu's floating point unint. */
int crosvm_vcpu_set_fpu(struct crosvm_vcpu*, const struct kvm_fpu*);

/* Gets the state of the vcpu's debug registers. */
int crosvm_vcpu_get_debugregs(struct crosvm_vcpu*, struct kvm_debugregs*);
/* Sets the state of the vcpu's debug registers */
int crosvm_vcpu_set_debugregs(struct crosvm_vcpu*, const struct kvm_debugregs*);

/* Gets the MSRs of the vcpu indicated by the index field of each entry. */
int crosvm_vcpu_get_msrs(struct crosvm_vcpu*, uint32_t __msr_count,
                         struct kvm_msr_entry *__msr_entries);
/* Sets the MSRs of the vcpu indicated by the index field of each entry. */
int crosvm_vcpu_set_msrs(struct crosvm_vcpu*, uint32_t __msr_count,
                         const struct kvm_msr_entry *__msr_entries);

/* Sets the responses to the cpuid instructions executed on this vcpu, */
int crosvm_vcpu_set_cpuid(struct crosvm_vcpu*, uint32_t __cpuid_count,
                          const struct kvm_cpuid_entry2 *__cpuid_entries);

/* Gets state of LAPIC of the VCPU. */
int crosvm_vcpu_get_lapic_state(struct crosvm_vcpu *,
                                struct kvm_lapic_state *__lapic_state);
/* Sets state of LAPIC of the VCPU. */
int crosvm_vcpu_set_lapic_state(struct crosvm_vcpu *,
                                const struct kvm_lapic_state *__lapic_state);

/* Gets the "multiprocessor state" of given VCPU. */
int crosvm_vcpu_get_mp_state(struct crosvm_vcpu *,
                             struct kvm_mp_state *__mp_state);
/* Sets the "multiprocessor state" of given VCPU. */
int crosvm_vcpu_set_mp_state(struct crosvm_vcpu *,
                             const struct kvm_mp_state *__mp_state);

#ifdef  __cplusplus
}
#endif

#endif