]>
Commit | Line | Data |
---|---|---|
9c5137ae SL |
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 */ | |
72f293de SL |
18 | LIST_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 | */ | |
23 | DEFINE_RWLOCK(acrn_vm_list_lock); | |
9c5137ae SL |
24 | |
25 | struct 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 | ||
88f537d5 | 37 | mutex_init(&vm->regions_mapping_lock); |
72f293de SL |
38 | INIT_LIST_HEAD(&vm->ioreq_clients); |
39 | spin_lock_init(&vm->ioreq_clients_lock); | |
9c5137ae SL |
40 | vm->vmid = vm_param->vmid; |
41 | vm->vcpu_num = vm_param->vcpu_num; | |
42 | ||
72f293de SL |
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); | |
9c5137ae | 50 | list_add(&vm->list, &acrn_vm_list); |
72f293de | 51 | write_unlock_bh(&acrn_vm_list_lock); |
9c5137ae | 52 | |
d8ad5151 | 53 | acrn_ioeventfd_init(vm); |
aa3b483f | 54 | acrn_irqfd_init(vm); |
9c5137ae SL |
55 | dev_dbg(acrn_dev.this_device, "VM %u created.\n", vm->vmid); |
56 | return vm; | |
57 | } | |
58 | ||
59 | int 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 | /* Remove from global VM list */ | |
72f293de | 68 | write_lock_bh(&acrn_vm_list_lock); |
9c5137ae | 69 | list_del_init(&vm->list); |
72f293de SL |
70 | write_unlock_bh(&acrn_vm_list_lock); |
71 | ||
d8ad5151 | 72 | acrn_ioeventfd_deinit(vm); |
aa3b483f | 73 | acrn_irqfd_deinit(vm); |
72f293de | 74 | acrn_ioreq_deinit(vm); |
aa3b483f | 75 | |
c7cf8d27 SL |
76 | if (vm->monitor_page) { |
77 | put_page(vm->monitor_page); | |
78 | vm->monitor_page = NULL; | |
79 | } | |
9c5137ae SL |
80 | |
81 | ret = hcall_destroy_vm(vm->vmid); | |
82 | if (ret < 0) { | |
83 | dev_err(acrn_dev.this_device, | |
84 | "Failed to destroy VM %u\n", vm->vmid); | |
85 | clear_bit(ACRN_VM_FLAG_DESTROYED, &vm->flags); | |
86 | return ret; | |
87 | } | |
88f537d5 SL |
88 | |
89 | acrn_vm_all_ram_unmap(vm); | |
90 | ||
9c5137ae SL |
91 | dev_dbg(acrn_dev.this_device, "VM %u destroyed.\n", vm->vmid); |
92 | vm->vmid = ACRN_INVALID_VMID; | |
93 | return 0; | |
94 | } | |
c7cf8d27 SL |
95 | |
96 | /** | |
1c15b334 | 97 | * acrn_msi_inject() - Inject a MSI interrupt into a User VM |
c7cf8d27 SL |
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 | */ | |
104 | int 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 | } |