cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vm.c (2978B)


      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}