KVM源代码解读:linux-3.17.4\include\linux\kvm_host.h

#ifndef __KVM_HOST_H

#define __KVM_HOST_H

 

/*

 * This work is licensed under the terms of the GNU GPL, version 2.  See

 * the COPYING file in the top-level directory.

 */

 

#include <linux/types.h>

#include <linux/hardirq.h>

#include <linux/list.h>

#include <linux/mutex.h>

#include <linux/spinlock.h>

#include <linux/signal.h>

#include <linux/sched.h>

#include <linux/bug.h>

#include <linux/mm.h>

#include <linux/mmu_notifier.h>

#include <linux/preempt.h>

#include <linux/msi.h>

#include <linux/slab.h>

#include <linux/rcupdate.h>

#include <linux/ratelimit.h>

#include <linux/err.h>

#include <linux/irqflags.h>

#include <linux/context_tracking.h>

#include <asm/signal.h>

 

#include <linux/kvm.h>

#include <linux/kvm_para.h>

 

#include <linux/kvm_types.h>

 

#include <asm/kvm_host.h>

 

#ifndef KVM_MMIO_SIZE

#define KVM_MMIO_SIZE 8

#endif

 

/*

 * The bit 16 ~ bit 31 of kvm_memory_region::flags are internally used

 * in kvm, other bits are visible for userspace which are defined in

 * include/linux/kvm_h.

 */

#define KVM_MEMSLOT_INVALID     (1UL << 16)

 

/* Two fragments for cross MMIO pages. 交叉MMIO页两个片段*/

#define KVM_MAX_MMIO_FRAGMENTS   2

 

/*

 * For the normal pfn, the highest 12 bits should be zero,

 * so we can mask bit 62 ~ bit 52  to indicate the error pfn,

 * mask bit 63 to indicate the noslot pfn.

 */

 /*

 对于正常的pfn,最高的12位应该为0

 因此将52-62位用来表明错误的pfn

 第63位表示没有内存槽的pfn

*/

#define KVM_PFN_ERR_MASK     (0x7ffULL << 52)

#define KVM_PFN_ERR_NOSLOT_MASK   (0xfffULL << 52)

#define KVM_PFN_NOSLOT        (0x1ULL << 63)

 

#define KVM_PFN_ERR_FAULT    (KVM_PFN_ERR_MASK)

#define KVM_PFN_ERR_HWPOISON  (KVM_PFN_ERR_MASK + 1)

#define KVM_PFN_ERR_RO_FAULT    (KVM_PFN_ERR_MASK + 2)

 

/*

 * error pfns indicate that the gfn is in slot but faild to

 * translate it to pfn on host.

 */

 /*

gfn在内存槽但是翻译成pfn失败

*/

static inline bool is_error_pfn(pfn_t pfn)

{

      return !!(pfn & KVM_PFN_ERR_MASK);

}

 

/*

 * error_noslot pfns indicate that the gfn can not be

 * translated to pfn - it is not in slot or failed to

 * translate it to pfn.

 */

  /*

不能翻译成pfn,即gfn不在内存槽或者翻译失败

*/

static inline bool is_error_noslot_pfn(pfn_t pfn)

{

      return !!(pfn & KVM_PFN_ERR_NOSLOT_MASK);

}

 

/* noslot pfn indicates that the gfn is not in slot. */

//不在内存槽中的pfn表明gfn不在内存槽中

static inline bool is_noslot_pfn(pfn_t pfn)

{

      return pfn == KVM_PFN_NOSLOT;

}

 

/*

 * architectures with KVM_HVA_ERR_BAD other than PAGE_OFFSET (e.g. s390)

 * provide own defines and kvm_is_error_hva

 */

#ifndef KVM_HVA_ERR_BAD

 

#define KVM_HVA_ERR_BAD      (PAGE_OFFSET)

#define KVM_HVA_ERR_RO_BAD (PAGE_OFFSET + PAGE_SIZE)

 

static inline bool kvm_is_error_hva(unsigned long addr)

{

      return addr >= PAGE_OFFSET;

}

 

#endif

 

#define KVM_ERR_PTR_BAD_PAGE    (ERR_PTR(-ENOENT))

 

static inline bool is_error_page(struct page *page)

{

      return IS_ERR(page);

}

 

/*

 * vcpu->requests bit members    ,vcpu请求所在的位号

 */

#define KVM_REQ_TLB_FLUSH          0

#define KVM_REQ_MIGRATE_TIMER      1

#define KVM_REQ_REPORT_TPR_ACCESS  2

#define KVM_REQ_MMU_RELOAD         3

#define KVM_REQ_TRIPLE_FAULT       4

#define KVM_REQ_PENDING_TIMER      5

#define KVM_REQ_UNHALT             6

#define KVM_REQ_MMU_SYNC           7

#define KVM_REQ_CLOCK_UPDATE       8

#define KVM_REQ_KICK               9

#define KVM_REQ_DEACTIVATE_FPU    10

#define KVM_REQ_EVENT             11

#define KVM_REQ_APF_HALT          12

#define KVM_REQ_STEAL_UPDATE      13

#define KVM_REQ_NMI               14

#define KVM_REQ_PMU               15

#define KVM_REQ_PMI               16

#define KVM_REQ_WATCHDOG          17

#define KVM_REQ_MASTERCLOCK_UPDATE 18

#define KVM_REQ_MCLOCK_INPROGRESS 19

#define KVM_REQ_EPR_EXIT          20

#define KVM_REQ_SCAN_IOAPIC       21

#define KVM_REQ_GLOBAL_CLOCK_UPDATE 22

#define KVM_REQ_ENABLE_IBS        23

#define KVM_REQ_DISABLE_IBS       24

 

#define KVM_USERSPACE_IRQ_SOURCE_ID         0

#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID     1

 

struct kvm;

struct kvm_vcpu;

extern struct kmem_cache *kvm_vcpu_cache;

 

extern spinlock_t kvm_lock;

extern struct list_head vm_list;

 

struct kvm_io_range {

      gpa_t addr;

      int len;

      struct kvm_io_device *dev;

};

 

#define NR_IOBUS_DEVS 1000

//KVM虚拟机中的I/O总线,一条总线对应一个kvm_io_bus结构体,如ISA总线、PCI总线。

struct kvm_io_bus {

      int dev_count;

      int ioeventfd_count;

      struct kvm_io_range range[];

};

//5种kvm总线枚举

enum kvm_bus {

      KVM_MMIO_BUS,

      KVM_PIO_BUS,

      KVM_VIRTIO_CCW_NOTIFY_BUS,

      KVM_FAST_MMIO_BUS,

      KVM_NR_BUSES

};

 

int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,

                int len, const void *val);

int kvm_io_bus_write_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,

                     int len, const void *val, long cookie);

int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len,

               void *val);

int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,

                     int len, struct kvm_io_device *dev);

int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,

                       struct kvm_io_device *dev);

 

#ifdef CONFIG_KVM_ASYNC_PF

struct kvm_async_pf {

      struct work_struct work;

      struct list_head link;

      struct list_head queue;

      struct kvm_vcpu *vcpu;

      struct mm_struct *mm;

      gva_t gva;

      unsigned long addr;

      struct kvm_arch_async_pf arch;

      bool   wakeup_all;

};

 

void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu);

void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu);

int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,

                  struct kvm_arch_async_pf *arch);

int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu);

#endif

//客户4种模式

enum {

      OUTSIDE_GUEST_MODE,

      IN_GUEST_MODE,

      EXITING_GUEST_MODE,

      READING_SHADOW_PAGE_TABLES,

};

 

/*

 * Sometimes a large or cross-page mmio needs to be broken up into separate

 * exits for userspace servicing.将大页或者跨页的分段

 */

 

struct kvm_mmio_fragment {

      gpa_t gpa;

      void *data;

      unsigned len;

};

 

struct kvm_vcpu {

      struct kvm *kvm;//定义kvm结构体

#ifdef CONFIG_PREEMPT_NOTIFIERS//如果定义了抢占通知符

      struct preempt_notifier preempt_notifier;

#endif

      int cpu;

      int vcpu_id;//对应的vcpu的id

      int srcu_idx;

      int mode;

      unsigned long requests;

      unsigned long guest_debug;

 

      struct mutex mutex;

      struct kvm_run *run;//VCPU的运行时参数,其中保存了寄存器信息、内存信息、虚拟机状态等各种动态信息。

 

      int fpu_active;

      int guest_fpu_loaded, guest_xcr0_loaded;

      wait_queue_head_t wq;

      struct pid *pid;

      int sigset_active;

      sigset_t sigset;

      struct kvm_vcpu_stat stat;//虚拟cpu的状态信息

 

#ifdef CONFIG_HAS_IOMEM//如果定义了i/o内存

      int mmio_needed;

      int mmio_read_completed;

      int mmio_is_write;

      int mmio_cur_fragment;

      int mmio_nr_fragments;

      struct kvm_mmio_fragment mmio_fragments[KVM_MAX_MMIO_FRAGMENTS];

#endif

 

#ifdef CONFIG_KVM_ASYNC_PF//如果定义了kvm异步

      struct {

           u32 queued;

           struct list_head queue;

           struct list_head done;

           spinlock_t lock;

      } async_pf;

#endif

 

#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT//轻松拦截/截获

      /*

       * Cpu relax intercept or pause loop exit optimization

       * in_spin_loop: set when a vcpu does a pause loop exit

       *  or cpu relax intercepted.

       * dy_eligible: indicates whether vcpu is eligible for directed yield.

       */

      struct {

           bool in_spin_loop;

           bool dy_eligible;

      } spin_loop;

#endif

      bool preempted;

      struct kvm_vcpu_arch arch;//存储有KVM虚拟机的运行时参数,如定时器、中断、内存槽等方面的信息。

};

 

static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)

{

      return cmpxchg(&vcpu->mode, IN_GUEST_MODE, EXITING_GUEST_MODE);

}

 

/*

 * Some of the bitops functions do not support too long bitmaps.

 * This number must be determined not to exceed such limits.

 */

#define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1)

//kvm内存槽操作的数据结构

struct kvm_memory_slot {

      gfn_t base_gfn;

      unsigned long npages;

      unsigned long *dirty_bitmap;

      struct kvm_arch_memory_slot arch;

      unsigned long userspace_addr;

      u32 flags;

      short id;

};

 

static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot)

{

      return ALIGN(memslot->npages, BITS_PER_LONG) / 8;

}

 

struct kvm_s390_adapter_int {

      u64 ind_addr;

      u64 summary_addr;

      u64 ind_offset;

      u32 summary_offset;

      u32 adapter_id;

};

 

struct kvm_kernel_irq_routing_entry {

      u32 gsi;

      u32 type;

      int (*set)(struct kvm_kernel_irq_routing_entry *e,

              struct kvm *kvm, int irq_source_id, int level,

              bool line_status);

      union {

           struct {

                 unsigned irqchip;

                 unsigned pin;

           } irqchip;

           struct msi_msg msi;

           struct kvm_s390_adapter_int adapter;

      };

      struct hlist_node link;

};

 

struct kvm_irq_routing_table;

 

#ifndef KVM_PRIVATE_MEM_SLOTS

#define KVM_PRIVATE_MEM_SLOTS 0

#endif

 

#ifndef KVM_MEM_SLOTS_NUM

#define KVM_MEM_SLOTS_NUM (KVM_USER_MEM_SLOTS + KVM_PRIVATE_MEM_SLOTS)

#endif

 

/*

 * Note:

 * memslots are not sorted by id anymore, please use id_to_memslot()

 * to get the memslot by its id.

 */

 //kvm内存槽数据结构

struct kvm_memslots {

      u64 generation;

      //#define KVM_MEM_SLOTS_NUM (KVM_USER_MEM_SLOTS + KVM_PRIVATE_MEM_SLOTS)

      struct kvm_memory_slot memslots[KVM_MEM_SLOTS_NUM];

      /* The mapping table from slot id to the index in memslots[]. */

      short id_to_index[KVM_MEM_SLOTS_NUM];

};

 

struct kvm {

      spinlock_t mmu_lock;

      struct mutex slots_lock;

      struct mm_struct *mm; /* userspace tied to this vm */

      struct kvm_memslots *memslots;//KVM虚拟机所分配到的内存slot,以数组形式存储这些slot的地址信息。

      struct srcu_struct srcu;

      struct srcu_struct irq_srcu;

#ifdef CONFIG_KVM_APIC_ARCHITECTURE

      u32 bsp_vcpu_id;

#endif

      struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];//KVM虚拟机中包含的vCPU结构体,一个虚拟CPU对应一个vCPU结构体。

      atomic_t online_vcpus;

      int last_boosted_vcpu;

      struct list_head vm_list;

      struct mutex lock;

      struct kvm_io_bus *buses[KVM_NR_BUSES];//KVM虚拟机中的I/O总线,一条总线对应一个kvm_io_bus结构体,如ISA总线、PCI总线。

#ifdef CONFIG_HAVE_KVM_EVENTFD

      struct {

           spinlock_t        lock;

           struct list_head  items;

           struct list_head  resampler_list;

           struct mutex      resampler_lock;

      } irqfds;

      struct list_head ioeventfds;

#endif

      struct kvm_vm_stat stat;//KVM虚拟机中的页表、MMU等运行时状态信息。

      struct kvm_arch arch;//KVM的软件arch方面所需要的一些参数

      atomic_t users_count;

#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET

      struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;

      spinlock_t ring_lock;

      struct list_head coalesced_zones;

#endif

 

      struct mutex irq_lock;

#ifdef CONFIG_HAVE_KVM_IRQCHIP

      /*

       * Update side is protected by irq_lock.

       */

      struct kvm_irq_routing_table __rcu *irq_routing;

      struct hlist_head mask_notifier_list;

#endif

#ifdef CONFIG_HAVE_KVM_IRQFD

      struct hlist_head irq_ack_notifier_list;

#endif

 

#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)

      struct mmu_notifier mmu_notifier;

      unsigned long mmu_notifier_seq;

      long mmu_notifier_count;

#endif

      long tlbs_dirty;//TLB高速缓存脏位

      //在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点。

      struct list_head devices;//设备链表

};

 

#define kvm_err(fmt, ...) \

      pr_err("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)

#define kvm_info(fmt, ...) \

      pr_info("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)

#define kvm_debug(fmt, ...) \

      pr_debug("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)

#define kvm_pr_unimpl(fmt, ...) \

      pr_err_ratelimited("kvm [%i]: " fmt, \

                    task_tgid_nr(current), ## __VA_ARGS__)

 

/* The guest did something we don‘t support. */

#define vcpu_unimpl(vcpu, fmt, ...)                        \

      kvm_pr_unimpl("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)

//获得相应vcpu

static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)

{

      smp_rmb();

      return kvm->vcpus[i];

}

//后面都会用到,对每个vcpu进行操作

#define kvm_for_each_vcpu(idx, vcpup, kvm) \

      for (idx = 0; \

           idx < atomic_read(&kvm->online_vcpus) && \

           (vcpup = kvm_get_vcpu(kvm, idx)) != NULL; \

           idx++)

//对每个memslot进行操作

#define kvm_for_each_memslot(memslot, slots)  \

      for (memslot = &slots->memslots[0];     \

            memslot < slots->memslots + KVM_MEM_SLOTS_NUM && memslot->npages;\

           memslot++)

 

int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);

void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);

 

int __must_check vcpu_load(struct kvm_vcpu *vcpu);

void vcpu_put(struct kvm_vcpu *vcpu);

 

#ifdef CONFIG_HAVE_KVM_IRQFD

int kvm_irqfd_init(void);

void kvm_irqfd_exit(void);

#else

static inline int kvm_irqfd_init(void)

{

      return 0;

}

 

static inline void kvm_irqfd_exit(void)

{

}

#endif

int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,

             struct module *module);

void kvm_exit(void);

 

void kvm_get_kvm(struct kvm *kvm);

void kvm_put_kvm(struct kvm *kvm);

 

static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm)

{

      return rcu_dereference_check(kvm->memslots,

                 srcu_read_lock_held(&kvm->srcu)

                 || lockdep_is_held(&kvm->slots_lock));

}

//通过id获得内存槽

static inline struct kvm_memory_slot *

id_to_memslot(struct kvm_memslots *slots, int id)

{

      int index = slots->id_to_index[id];

      struct kvm_memory_slot *slot;

 

      slot = &slots->memslots[index];

 

      WARN_ON(slot->id != id);

      return slot;

}

//设置用户内存区域

/*

 * KVM_SET_USER_MEMORY_REGION ioctl allows the following operations:

 * - create a new memory slot

 * - delete an existing memory slot

 * - modify an existing memory slot

 *   -- move it in the guest physical memory space

 *   -- just change its flags

 *

 * Since flags can be changed by some of these operations, the following

 * differentiation is the best we can do for __kvm_set_memory_region():

 */

 //改变内存的4种操作的枚举类型

enum kvm_mr_change {

      KVM_MR_CREATE,

      KVM_MR_DELETE,

      KVM_MR_MOVE,

      KVM_MR_FLAGS_ONLY,

};

 

int kvm_set_memory_region(struct kvm *kvm,

                   struct kvm_userspace_memory_region *mem);

int __kvm_set_memory_region(struct kvm *kvm,

                     struct kvm_userspace_memory_region *mem);

void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,

                    struct kvm_memory_slot *dont);

int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,

                     unsigned long npages);

void kvm_arch_memslots_updated(struct kvm *kvm);

int kvm_arch_prepare_memory_region(struct kvm *kvm,

                      struct kvm_memory_slot *memslot,

                      struct kvm_userspace_memory_region *mem,

                      enum kvm_mr_change change);

void kvm_arch_commit_memory_region(struct kvm *kvm,

                      struct kvm_userspace_memory_region *mem,

                      const struct kvm_memory_slot *old,

                      enum kvm_mr_change change);

bool kvm_largepages_enabled(void);

void kvm_disable_largepages(void);

/* flush all memory translations */

void kvm_arch_flush_shadow_all(struct kvm *kvm);

/* flush memory translations pointing to ‘slot‘ */

void kvm_arch_flush_shadow_memslot(struct kvm *kvm,

                         struct kvm_memory_slot *slot);

 

int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages,

                     int nr_pages);

 

struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);

unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);

unsigned long gfn_to_hva_prot(struct kvm *kvm, gfn_t gfn, bool *writable);

unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn);

void kvm_release_page_clean(struct page *page);

void kvm_release_page_dirty(struct page *page);

void kvm_set_page_accessed(struct page *page);

 

pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn);

pfn_t gfn_to_pfn_async(struct kvm *kvm, gfn_t gfn, bool *async,

                  bool write_fault, bool *writable);

pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);

pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,

                 bool *writable);

pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn);

pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn);

 

void kvm_release_pfn_clean(pfn_t pfn);

void kvm_set_pfn_dirty(pfn_t pfn);

void kvm_set_pfn_accessed(pfn_t pfn);

void kvm_get_pfn(pfn_t pfn);

 

int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,

                 int len);

int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,

                   unsigned long len);

int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len);

int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,

                    void *data, unsigned long len);

int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data,

                  int offset, int len);

int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data,

               unsigned long len);

int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,

                    void *data, unsigned long len);

int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,

                       gpa_t gpa, unsigned long len);

int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);

int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len);

struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);

int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);

unsigned long kvm_host_page_size(struct kvm *kvm, gfn_t gfn);

void mark_page_dirty(struct kvm *kvm, gfn_t gfn);

 

void kvm_vcpu_block(struct kvm_vcpu *vcpu);

void kvm_vcpu_kick(struct kvm_vcpu *vcpu);

int kvm_vcpu_yield_to(struct kvm_vcpu *target);

void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu);

void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);

void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);

 

void kvm_flush_remote_tlbs(struct kvm *kvm);

void kvm_reload_remote_mmus(struct kvm *kvm);

void kvm_make_mclock_inprogress_request(struct kvm *kvm);

void kvm_make_scan_ioapic_request(struct kvm *kvm);

 

long kvm_arch_dev_ioctl(struct file *filp,

                 unsigned int ioctl, unsigned long arg);

long kvm_arch_vcpu_ioctl(struct file *filp,

                  unsigned int ioctl, unsigned long arg);

int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf);

 

int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext);

 

int kvm_get_dirty_log(struct kvm *kvm,

                 struct kvm_dirty_log *log, int *is_dirty);

int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,

                      struct kvm_dirty_log *log);

 

int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,

                 bool line_status);

long kvm_arch_vm_ioctl(struct file *filp,

                  unsigned int ioctl, unsigned long arg);

 

int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);

int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);

 

int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,

                          struct kvm_translation *tr);

 

int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs);

int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs);

int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,

                        struct kvm_sregs *sregs);

int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,

                        struct kvm_sregs *sregs);

int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,

                          struct kvm_mp_state *mp_state);

int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,

                          struct kvm_mp_state *mp_state);

int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,

                            struct kvm_guest_debug *dbg);

int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);

 

int kvm_arch_init(void *opaque);

void kvm_arch_exit(void);

 

int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu);

void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);

 

void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu);

void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu);

void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu);

struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id);

int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu);

int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu);

void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu);

 

int kvm_arch_hardware_enable(void *garbage);

void kvm_arch_hardware_disable(void *garbage);

int kvm_arch_hardware_setup(void);

void kvm_arch_hardware_unsetup(void);

void kvm_arch_check_processor_compat(void *rtn);

int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);

int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);

 

void *kvm_kvzalloc(unsigned long size);

void kvm_kvfree(const void *addr);

 

#ifndef __KVM_HAVE_ARCH_VM_ALLOC

static inline struct kvm *kvm_arch_alloc_vm(void)

{

      return kzalloc(sizeof(struct kvm), GFP_KERNEL);

}

 

static inline void kvm_arch_free_vm(struct kvm *kvm)

{

      kfree(kvm);

}

#endif

 

#ifdef __KVM_HAVE_ARCH_NONCOHERENT_DMA

void kvm_arch_register_noncoherent_dma(struct kvm *kvm);

void kvm_arch_unregister_noncoherent_dma(struct kvm *kvm);

bool kvm_arch_has_noncoherent_dma(struct kvm *kvm);

#else

static inline void kvm_arch_register_noncoherent_dma(struct kvm *kvm)

{

}

 

static inline void kvm_arch_unregister_noncoherent_dma(struct kvm *kvm)

{

}

 

static inline bool kvm_arch_has_noncoherent_dma(struct kvm *kvm)

{

      return false;

}

#endif

 

static inline wait_queue_head_t *kvm_arch_vcpu_wq(struct kvm_vcpu *vcpu)

{

#ifdef __KVM_HAVE_ARCH_WQP

      return vcpu->arch.wqp;

#else

      return &vcpu->wq;

#endif

}

 

int kvm_arch_init_vm(struct kvm *kvm, unsigned long type);

void kvm_arch_destroy_vm(struct kvm *kvm);

void kvm_arch_sync_events(struct kvm *kvm);

 

int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);

void kvm_vcpu_kick(struct kvm_vcpu *vcpu);

 

bool kvm_is_mmio_pfn(pfn_t pfn);

//中断请求确认通知符

struct kvm_irq_ack_notifier {

      struct hlist_node link;

      unsigned gsi;

      void (*irq_acked)(struct kvm_irq_ack_notifier *kian);

};

//分配内核设备

struct kvm_assigned_dev_kernel {

      struct kvm_irq_ack_notifier ack_notifier;

      struct list_head list;

      int assigned_dev_id;

      int host_segnr;

      int host_busnr;

      int host_devfn;

      unsigned int entries_nr;

      int host_irq;

      bool host_irq_disabled;

      bool pci_2_3;

      struct msix_entry *host_msix_entries;

      int guest_irq;

      struct msix_entry *guest_msix_entries;

      unsigned long irq_requested_type;

      int irq_source_id;

      int flags;

      struct pci_dev *dev;

      struct kvm *kvm;

      spinlock_t intx_lock;

      spinlock_t intx_mask_lock;

      char irq_name[32];

      struct pci_saved_state *pci_saved_state;//保存pci设备的状态

};

 

struct kvm_irq_mask_notifier {

      void (*func)(struct kvm_irq_mask_notifier *kimn, bool masked);

      int irq;

      struct hlist_node link;

};

 

void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,

                          struct kvm_irq_mask_notifier *kimn);

void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,

                            struct kvm_irq_mask_notifier *kimn);

void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,

                      bool mask);

 

int kvm_irq_map_gsi(struct kvm *kvm,

               struct kvm_kernel_irq_routing_entry *entries, int gsi);

int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin);

 

int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,

           bool line_status);

int kvm_set_irq_inatomic(struct kvm *kvm, int irq_source_id, u32 irq, int level);

int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm,

           int irq_source_id, int level, bool line_status);

bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin);

void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);

void kvm_register_irq_ack_notifier(struct kvm *kvm,

                         struct kvm_irq_ack_notifier *kian);

void kvm_unregister_irq_ack_notifier(struct kvm *kvm,

                         struct kvm_irq_ack_notifier *kian);

int kvm_request_irq_source_id(struct kvm *kvm);

void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);

 

#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT

int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot);

void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot);

int kvm_iommu_map_guest(struct kvm *kvm);

int kvm_iommu_unmap_guest(struct kvm *kvm);

int kvm_assign_device(struct kvm *kvm,

                 struct kvm_assigned_dev_kernel *assigned_dev);

int kvm_deassign_device(struct kvm *kvm,

                 struct kvm_assigned_dev_kernel *assigned_dev);

#else

static inline int kvm_iommu_map_pages(struct kvm *kvm,

                            struct kvm_memory_slot *slot)

{

      return 0;

}

 

static inline void kvm_iommu_unmap_pages(struct kvm *kvm,

                             struct kvm_memory_slot *slot)

{

}

 

static inline int kvm_iommu_unmap_guest(struct kvm *kvm)

{

      return 0;

}

#endif

//进入客户模式

static inline void kvm_guest_enter(void)

{

      unsigned long flags;

 

      BUG_ON(preemptible());

 

      local_irq_save(flags);

      guest_enter();

      local_irq_restore(flags);

 

      /* KVM does not hold any references to rcu protected data when it

       * switches CPU into a guest mode. In fact switching to a guest mode

       * is very similar to exiting to userspace from rcu point of view. In

       * addition CPU may stay in a guest mode for quite a long time (up to

       * one time slice). Lets treat guest mode as quiescent state静止状态, just like

       * we do with user-mode execution.

       */

      rcu_virt_note_context_switch(smp_processor_id());

}

//退出客户模式

static inline void kvm_guest_exit(void)

{

      unsigned long flags;

 

      local_irq_save(flags);

      guest_exit();

      local_irq_restore(flags);

}

 

/*

 * search_memslots() and __gfn_to_memslot() are here because they are

 * used in non-modular code in arch/powerpc/kvm/book3s_hv_rm_mmu.c.

 * gfn_to_memslot() itself isn‘t here as an inline because that would

 * bloat other code too much.

 */

 //查找内存槽,用for循环

static inline struct kvm_memory_slot *

search_memslots(struct kvm_memslots *slots, gfn_t gfn)

{

      struct kvm_memory_slot *memslot;

 

      kvm_for_each_memslot(memslot, slots)

           if (gfn >= memslot->base_gfn &&

                 gfn < memslot->base_gfn + memslot->npages)

                 return memslot;

 

      return NULL;

}

//函数作用筒search_memslots()

static inline struct kvm_memory_slot *

__gfn_to_memslot(struct kvm_memslots *slots, gfn_t gfn)

{

      return search_memslots(slots, gfn);

}

//gfn到hva内存槽

static inline unsigned long

__gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn)

{

      return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE;

}

//获得内存槽的id

static inline int memslot_id(struct kvm *kvm, gfn_t gfn)

{

      return gfn_to_memslot(kvm, gfn)->id;

}

//根据定义的页的大小,比如4KB,取定PAGE_SHIFT的值,其值即是页框号和地址的左移或者右移的位数

static inline gfn_t

hva_to_gfn_memslot(unsigned long hva, struct kvm_memory_slot *slot)

{

      gfn_t gfn_offset = (hva - slot->userspace_addr) >> PAGE_SHIFT;

 

      return slot->base_gfn + gfn_offset;

}

 

static inline gpa_t gfn_to_gpa(gfn_t gfn)

{

      return (gpa_t)gfn << PAGE_SHIFT;

}

 

static inline gfn_t gpa_to_gfn(gpa_t gpa)

{

      return (gfn_t)(gpa >> PAGE_SHIFT);

}

 

static inline hpa_t pfn_to_hpa(pfn_t pfn)

{

      return (hpa_t)pfn << PAGE_SHIFT;

}

//判断gpa是否错误

static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa)

{

      unsigned long hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));

 

      return kvm_is_error_hva(hva);

}

 

static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu)

{

      set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests);

}

//kvm的两种状态,VM和VCPU

enum kvm_stat_kind {

      KVM_STAT_VM,

      KVM_STAT_VCPU,

};

 

struct kvm_stats_debugfs_item {

      const char *name;

      int offset;

      enum kvm_stat_kind kind;

      struct dentry *dentry;

};

extern struct kvm_stats_debugfs_item debugfs_entries[];

extern struct dentry *kvm_debugfs_dir;

 

#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)

static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)

{

      if (unlikely(kvm->mmu_notifier_count))

           return 1;

      /*

       * Ensure the read of mmu_notifier_count happens before the read

       * of mmu_notifier_seq.  This interacts with the smp_wmb() in

       * mmu_notifier_invalidate_range_end to make sure that the caller

       * either sees the old (non-zero) value of mmu_notifier_count or

       * the new (incremented) value of mmu_notifier_seq.

       * PowerPC Book3s HV KVM calls this under a per-page lock

       * rather than under kvm->mmu_lock, for scalability, so

       * can‘t rely on kvm->mmu_lock to keep things ordered.

       */

      smp_rmb();

      if (kvm->mmu_notifier_seq != mmu_seq)

           return 1;

      return 0;

}

#endif

 

#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING

 

#ifdef CONFIG_S390

#define KVM_MAX_IRQ_ROUTES 4096 //FIXME: we can have more than that...

#else

#define KVM_MAX_IRQ_ROUTES 1024

#endif

 

int kvm_setup_default_irq_routing(struct kvm *kvm);

int kvm_set_irq_routing(struct kvm *kvm,

                 const struct kvm_irq_routing_entry *entries,

                 unsigned nr,

                 unsigned flags);

int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,

                   const struct kvm_irq_routing_entry *ue);

void kvm_free_irq_routing(struct kvm *kvm);

 

#else

 

static inline void kvm_free_irq_routing(struct kvm *kvm) {}

 

#endif

 

int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);

 

#ifdef CONFIG_HAVE_KVM_EVENTFD

 

void kvm_eventfd_init(struct kvm *kvm);

int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);

 

#ifdef CONFIG_HAVE_KVM_IRQFD

int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args);

void kvm_irqfd_release(struct kvm *kvm);

void kvm_irq_routing_update(struct kvm *);

#else

static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)

{

      return -EINVAL;

}

 

static inline void kvm_irqfd_release(struct kvm *kvm) {}

#endif

 

#else

 

static inline void kvm_eventfd_init(struct kvm *kvm) {}

 

static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)

{

      return -EINVAL;

}

 

static inline void kvm_irqfd_release(struct kvm *kvm) {}

 

#ifdef CONFIG_HAVE_KVM_IRQCHIP

static inline void kvm_irq_routing_update(struct kvm *kvm)

{

}

#endif

 

static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)

{

      return -ENOSYS;

}

 

#endif /* CONFIG_HAVE_KVM_EVENTFD */

 

#ifdef CONFIG_KVM_APIC_ARCHITECTURE

static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)

{

      return vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id;

}

 

bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu);

 

#else

 

static inline bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) { return true; }

 

#endif

 

#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT

 

long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,

                        unsigned long arg);

 

void kvm_free_all_assigned_devices(struct kvm *kvm);

 

#else

 

static inline long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,

                                  unsigned long arg)

{

      return -ENOTTY;

}

 

static inline void kvm_free_all_assigned_devices(struct kvm *kvm) {}

 

#endif

 

static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)

{

      set_bit(req, &vcpu->requests);

}

 

static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu)

{

      if (test_bit(req, &vcpu->requests)) {

           clear_bit(req, &vcpu->requests);

           return true;

      } else {

           return false;

      }

}

 

extern bool kvm_rebooting;

 

struct kvm_device_ops;

//kvm设备操作结构体

struct kvm_device {

      struct kvm_device_ops *ops;//kvm设备操作符

      struct kvm *kvm;

      void *private;

      struct list_head vm_node;//设备的双向链表

};

 

/* create, destroy, and name are mandatory 强制性的*/

//设备操作符数据结构

struct kvm_device_ops {

      const char *name;

      int (*create)(struct kvm_device *dev, u32 type);

 

      /*

       * Destroy is responsible for freeing dev.

       *

       * Destroy may be called before or after destructors are called

       * on emulated I/O regions, depending on whether a reference is

       * held by a vcpu or other kvm component that gets destroyed

       * after the emulated I/O.

       */

      void (*destroy)(struct kvm_device *dev);

 

      int (*set_attr)(struct kvm_device *dev, struct kvm_device_attr *attr);

      int (*get_attr)(struct kvm_device *dev, struct kvm_device_attr *attr);

      int (*has_attr)(struct kvm_device *dev, struct kvm_device_attr *attr);

      long (*ioctl)(struct kvm_device *dev, unsigned int ioctl,

                 unsigned long arg);

};

 

void kvm_device_get(struct kvm_device *dev);

void kvm_device_put(struct kvm_device *dev);

struct kvm_device *kvm_device_from_filp(struct file *filp);

 

extern struct kvm_device_ops kvm_mpic_ops;

extern struct kvm_device_ops kvm_xics_ops;

extern struct kvm_device_ops kvm_vfio_ops;

extern struct kvm_device_ops kvm_arm_vgic_v2_ops;

extern struct kvm_device_ops kvm_flic_ops;

 

#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT

 

static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val)

{

      vcpu->spin_loop.in_spin_loop = val;

}

static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)

{

      vcpu->spin_loop.dy_eligible = val;

}

 

#else /* !CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */

 

static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val)

{

}

 

static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)

{

}

#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */

#endif

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。