linux/drivers/virt/acrn/vm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ACRN_HSM: Virtual Machine management
   4 *
   5 * Copyright (C) 2020 Intel Corporation. All rights reserved.
   6 *
   7 * Authors:
   8 *      Jason Chen CJ <jason.cj.chen@intel.com>
   9 *      Yakui Zhao <yakui.zhao@intel.com>
  10 */
  11#include <linux/io.h>
  12#include <linux/mm.h>
  13#include <linux/slab.h>
  14
  15#include "acrn_drv.h"
  16
  17/* List of VMs */
  18LIST_HEAD(acrn_vm_list);
  19/*
  20 * acrn_vm_list is read in a worker thread which dispatch I/O requests and
  21 * is wrote in VM creation ioctl. Use the rwlock mechanism to protect it.
  22 */
  23DEFINE_RWLOCK(acrn_vm_list_lock);
  24
  25struct acrn_vm *acrn_vm_create(struct acrn_vm *vm,
  26                               struct acrn_vm_creation *vm_param)
  27{
  28        int ret;
  29
  30        ret = hcall_create_vm(virt_to_phys(vm_param));
  31        if (ret < 0 || vm_param->vmid == ACRN_INVALID_VMID) {
  32                dev_err(acrn_dev.this_device,
  33                        "Failed to create VM! Error: %d\n", ret);
  34                return NULL;
  35        }
  36
  37        mutex_init(&vm->regions_mapping_lock);
  38        INIT_LIST_HEAD(&vm->ioreq_clients);
  39        spin_lock_init(&vm->ioreq_clients_lock);
  40        vm->vmid = vm_param->vmid;
  41        vm->vcpu_num = vm_param->vcpu_num;
  42
  43        if (acrn_ioreq_init(vm, vm_param->ioreq_buf) < 0) {
  44                hcall_destroy_vm(vm_param->vmid);
  45                vm->vmid = ACRN_INVALID_VMID;
  46                return NULL;
  47        }
  48
  49        write_lock_bh(&acrn_vm_list_lock);
  50        list_add(&vm->list, &acrn_vm_list);
  51        write_unlock_bh(&acrn_vm_list_lock);
  52
  53        acrn_ioeventfd_init(vm);
  54        acrn_irqfd_init(vm);
  55        dev_dbg(acrn_dev.this_device, "VM %u created.\n", vm->vmid);
  56        return vm;
  57}
  58
  59int acrn_vm_destroy(struct acrn_vm *vm)
  60{
  61        int ret;
  62
  63        if (vm->vmid == ACRN_INVALID_VMID ||
  64            test_and_set_bit(ACRN_VM_FLAG_DESTROYED, &vm->flags))
  65                return 0;
  66
  67        ret = hcall_destroy_vm(vm->vmid);
  68        if (ret < 0) {
  69                dev_err(acrn_dev.this_device,
  70                        "Failed to destroy VM %u\n", vm->vmid);
  71                clear_bit(ACRN_VM_FLAG_DESTROYED, &vm->flags);
  72                return ret;
  73        }
  74
  75        /* Remove from global VM list */
  76        write_lock_bh(&acrn_vm_list_lock);
  77        list_del_init(&vm->list);
  78        write_unlock_bh(&acrn_vm_list_lock);
  79
  80        acrn_ioeventfd_deinit(vm);
  81        acrn_irqfd_deinit(vm);
  82        acrn_ioreq_deinit(vm);
  83
  84        if (vm->monitor_page) {
  85                put_page(vm->monitor_page);
  86                vm->monitor_page = NULL;
  87        }
  88
  89        acrn_vm_all_ram_unmap(vm);
  90
  91        dev_dbg(acrn_dev.this_device, "VM %u destroyed.\n", vm->vmid);
  92        vm->vmid = ACRN_INVALID_VMID;
  93        return 0;
  94}
  95
  96/**
  97 * acrn_msi_inject() - Inject a MSI interrupt into a User VM
  98 * @vm:         User VM
  99 * @msi_addr:   The MSI address
 100 * @msi_data:   The MSI data
 101 *
 102 * Return: 0 on success, <0 on error
 103 */
 104int acrn_msi_inject(struct acrn_vm *vm, u64 msi_addr, u64 msi_data)
 105{
 106        struct acrn_msi_entry *msi;
 107        int ret;
 108
 109        /* might be used in interrupt context, so use GFP_ATOMIC */
 110        msi = kzalloc(sizeof(*msi), GFP_ATOMIC);
 111        if (!msi)
 112                return -ENOMEM;
 113
 114        /*
 115         * msi_addr: addr[19:12] with dest vcpu id
 116         * msi_data: data[7:0] with vector
 117         */
 118        msi->msi_addr = msi_addr;
 119        msi->msi_data = msi_data;
 120        ret = hcall_inject_msi(vm->vmid, virt_to_phys(msi));
 121        if (ret < 0)
 122                dev_err(acrn_dev.this_device,
 123                        "Failed to inject MSI to VM %u!\n", vm->vmid);
 124        kfree(msi);
 125        return ret;
 126}
 127