/* * Copyright 2017 The ChromiumOS Authors * 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 #include #include #include #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 22 #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); /* * Enable an extended capability for the VM. Currently |__flags| and * |__args| must be zero. No values for |__capability| are supported, * so all calls will fail. */ int crosvm_enable_capability(struct crosvm*, uint32_t __capability, uint32_t __flags, uint64_t __args[4]); /* * 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); /* * Queries x86 hyper-v cpuid features which are emulated by kvm. */ int crosvm_get_hyperv_cpuid(struct crosvm_vcpu*, uint32_t __entry_count, struct kvm_cpuid_entry2 *__cpuid_entries, uint32_t *__out_count); /* * Queries kvm for list of supported MSRs. */ int crosvm_get_msr_index_list(struct crosvm*, uint32_t __entry_count, uint32_t *__msr_indices, 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); /* * Registers a range in the given address space that, when accessed via write, * will cause a notification in crosvm_vcpu_wait() but the VM will continue * running. * For this type of notification (where |no_resume| is set) the next call * should be crosvm_vcpu_wait() (without an inbetween call to * crosvm_vcpu_resume() ). * * The requested range must not overlap any prior (and currently active) * reservation to crosvm_reserve_range() or crosvm_reserve_async_write_range(). * * 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_async_write_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); /* Hint on what information is queried for a particular hypercall. */ struct crosvm_hint_detail { bool match_rax; bool match_rbx; bool match_rcx; bool match_rdx; uint8_t _reserved[4]; uint64_t rax; uint64_t rbx; uint64_t rcx; uint64_t rdx; bool send_sregs; bool send_debugregs; uint8_t _reserved2[6]; }; #ifdef static_assert static_assert(sizeof(struct crosvm_hint_detail) == 48, "extra padding in struct crosvm_hint_detail"); #endif /* Maximum # of hints that can be passed to crosvm_set_hypercall_hint(). */ #define CROSVM_MAX_HINT_COUNT 1 /* Maximum # of hint details that can be provided for a hint. */ #define CROSVM_MAX_HINT_DETAIL_COUNT 32 #define CROSVM_HINT_ON_WRITE 0x1 /* Hint on what information is queried for a particular hypercall. */ struct crosvm_hint { uint32_t hint_version; /* For now only 0 is defined. */ uint32_t _reserved; /* Must be zero. */ uint32_t address_space; /* Value from crosvm_address_space. */ uint16_t address_flags; /* 0: read/in; CROSVM_HINT_ON_WRITE: write/out. */ uint16_t details_count; /* # of elements in |details|. */ uint64_t address; union { struct crosvm_hint_detail *details; uint64_t _reserved2; /* forcing pointer length to 64-bit */ }; }; #ifdef static_assert static_assert(sizeof(struct crosvm_hint) == 32, "extra padding in struct crosvm_hint"); #endif /* * Sets performance hint(s) for a hypercall port. * * If a VM does an io access the specified |address_space|, |address| * (|address| must be non-zero), and direction (|address_flags|), then * crosvm will assume the plugin is likely to call crosvm_vcpu_get_regs() * (and thus utilize a cache to improve performance). * * Additional hints can be provided via |details| (the element length of * |details| is limited to CROSVM_MAX_HINT_DETAIL_COUNT) on when to also cache * information for crosvm_vcpu_get_sregs() and crosvm_vcpu_get_debugregs() * based on values in the vcpu registers. |match_XXX| indicates which of * 1 or more of |XXX| needs to be equal to the vcpu registers to be a match. * On a match |send_sregs| and |send_debugregs| are used to determine what * data to proactively cache for the plugin's use. Once a match is found * the remaining hints are not consulted. * * To remove all hints, pass 0 for |__hint_count|. The value of * |__hint_count| can be at most CROSVM_MAX_HINT_COUNT. Currently the API * is limited to 1 hint (i.e., |__hint_count| must be 0 or 1). Each call * to this API will replace the values specified by any prior call to this API. */ int crosvm_set_hypercall_hint(struct crosvm *, uint32_t __hints_count, const struct crosvm_hint* __hints); /* 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, const 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 *, const 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); /* Gets the current timestamp of kvmclock as seen by the VM. */ int crosvm_get_clock(struct crosvm *, struct kvm_clock_data *__clock_data); /* Sets the current timestamp of kvmclock for the VM. */ int crosvm_set_clock(struct crosvm *, const struct kvm_clock_data *__clock_data); /* 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*); /* * Allocates 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 allocation, returns a crosvm_io. Obtain the actual fd * by passing this result to crosvm_io_event_fd(). */ 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, /* * Hyper-V hypercall. */ CROSVM_VCPU_EVENT_KIND_HYPERV_HCALL, /* * Hyper-V synic change. */ CROSVM_VCPU_EVENT_KIND_HYPERV_SYNIC, }; 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. * * Larger I/O accesses are possible. "rep in" can generate I/Os larger * than 8 bytes, though such accesses can also be split into multiple * events. Currently kvm doesn't seem to batch "rep out" I/Os. */ uint32_t length; /* * True if the vcpu was attempting to write, false in case of an attempt * to read. */ uint8_t is_write; /* * Valid when |is_write| is true -- indicates that VM has continued * to run. The only next valid call for the vcpu is crosvm_vcpu_wait(). */ uint8_t no_resume; uint8_t _reserved[2]; } io_access; /* CROSVM_VCPU_EVENT_KIND_PAUSED */ void *user; /* CROSVM_VCPU_EVENT_KIND_HYPERV_HCALL */ struct { /* * The |input| and |params| members are populated for the plugin to use. * The |result| member is populated by the API to point to a uint64_t * that the plugin should update before resuming. */ uint64_t input; uint64_t *result; uint64_t params[2]; } hyperv_call; /* CROSVM_VCPU_EVENT_KIND_HYPERV_SYNIC */ struct { /* * The |msr|, |control|, |evt_page|, and |msg_page| fields are populated * for the plugin to use. */ uint32_t msr; uint32_t _reserved; uint64_t control; uint64_t evt_page; uint64_t msg_page; } hyperv_synic; 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 state of the vcpu's xcr registers. */ int crosvm_vcpu_get_xcrs(struct crosvm_vcpu*, struct kvm_xcrs*); /* Sets the state of the vcpu's xcr registers. */ int crosvm_vcpu_set_xcrs(struct crosvm_vcpu*, const struct kvm_xcrs*); /* 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, uint32_t *__out_count); /* 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); /* * Enable an extended capability for a vcpu. Currently |__flags| and * |__args| must be zero. The only permitted values for |__capability| * are KVM_CAP_HYPERV_SYNIC or KVM_CAP_HYPERV_SYNIC2, though the latter * also depends on kernel support. */ int crosvm_vcpu_enable_capability(struct crosvm_vcpu*, uint32_t __capability, uint32_t __flags, uint64_t __args[4]); /* 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); /* Gets currently pending exceptions, interrupts, NMIs, etc for VCPU. */ int crosvm_vcpu_get_vcpu_events(struct crosvm_vcpu *, struct kvm_vcpu_events *); /* Sets currently pending exceptions, interrupts, NMIs, etc for VCPU. */ int crosvm_vcpu_set_vcpu_events(struct crosvm_vcpu *, const struct kvm_vcpu_events *); #ifdef __cplusplus } #endif #endif