Commit | Line | Data |
---|---|---|
0f4b8257 VC |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2022 SiFive | |
4 | * | |
5 | * Authors: | |
6 | * Vincent Chen <vincent.chen@sifive.com> | |
7 | * Greentime Hu <greentime.hu@sifive.com> | |
8 | */ | |
9 | ||
10 | #include <linux/errno.h> | |
11 | #include <linux/err.h> | |
12 | #include <linux/kvm_host.h> | |
13 | #include <linux/uaccess.h> | |
14 | #include <asm/hwcap.h> | |
15 | #include <asm/kvm_vcpu_vector.h> | |
16 | #include <asm/vector.h> | |
17 | ||
18 | #ifdef CONFIG_RISCV_ISA_V | |
19 | void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu) | |
20 | { | |
21 | unsigned long *isa = vcpu->arch.isa; | |
22 | struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; | |
23 | ||
24 | cntx->sstatus &= ~SR_VS; | |
25 | if (riscv_isa_extension_available(isa, v)) { | |
26 | cntx->sstatus |= SR_VS_INITIAL; | |
27 | WARN_ON(!cntx->vector.datap); | |
28 | memset(cntx->vector.datap, 0, riscv_v_vsize); | |
29 | } else { | |
30 | cntx->sstatus |= SR_VS_OFF; | |
31 | } | |
32 | } | |
33 | ||
34 | static void kvm_riscv_vcpu_vector_clean(struct kvm_cpu_context *cntx) | |
35 | { | |
36 | cntx->sstatus &= ~SR_VS; | |
37 | cntx->sstatus |= SR_VS_CLEAN; | |
38 | } | |
39 | ||
40 | void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx, | |
41 | unsigned long *isa) | |
42 | { | |
43 | if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) { | |
44 | if (riscv_isa_extension_available(isa, v)) | |
45 | __kvm_riscv_vector_save(cntx); | |
46 | kvm_riscv_vcpu_vector_clean(cntx); | |
47 | } | |
48 | } | |
49 | ||
50 | void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx, | |
51 | unsigned long *isa) | |
52 | { | |
53 | if ((cntx->sstatus & SR_VS) != SR_VS_OFF) { | |
54 | if (riscv_isa_extension_available(isa, v)) | |
55 | __kvm_riscv_vector_restore(cntx); | |
56 | kvm_riscv_vcpu_vector_clean(cntx); | |
57 | } | |
58 | } | |
59 | ||
60 | void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx) | |
61 | { | |
62 | /* No need to check host sstatus as it can be modified outside */ | |
63 | if (riscv_isa_extension_available(NULL, v)) | |
64 | __kvm_riscv_vector_save(cntx); | |
65 | } | |
66 | ||
67 | void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx) | |
68 | { | |
69 | if (riscv_isa_extension_available(NULL, v)) | |
70 | __kvm_riscv_vector_restore(cntx); | |
71 | } | |
72 | ||
73 | int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu, | |
74 | struct kvm_cpu_context *cntx) | |
75 | { | |
76 | cntx->vector.datap = kmalloc(riscv_v_vsize, GFP_KERNEL); | |
77 | if (!cntx->vector.datap) | |
78 | return -ENOMEM; | |
79 | ||
80 | vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL); | |
81 | if (!vcpu->arch.host_context.vector.datap) | |
82 | return -ENOMEM; | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu) | |
88 | { | |
89 | kfree(vcpu->arch.guest_reset_context.vector.datap); | |
90 | kfree(vcpu->arch.host_context.vector.datap); | |
91 | } | |
92 | #endif | |
93 | ||
94 | static void *kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, | |
95 | unsigned long reg_num, | |
96 | size_t reg_size) | |
97 | { | |
98 | struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; | |
99 | void *reg_val; | |
100 | size_t vlenb = riscv_v_vsize / 32; | |
101 | ||
102 | if (reg_num < KVM_REG_RISCV_VECTOR_REG(0)) { | |
103 | if (reg_size != sizeof(unsigned long)) | |
104 | return NULL; | |
105 | switch (reg_num) { | |
106 | case KVM_REG_RISCV_VECTOR_CSR_REG(vstart): | |
107 | reg_val = &cntx->vector.vstart; | |
108 | break; | |
109 | case KVM_REG_RISCV_VECTOR_CSR_REG(vl): | |
110 | reg_val = &cntx->vector.vl; | |
111 | break; | |
112 | case KVM_REG_RISCV_VECTOR_CSR_REG(vtype): | |
113 | reg_val = &cntx->vector.vtype; | |
114 | break; | |
115 | case KVM_REG_RISCV_VECTOR_CSR_REG(vcsr): | |
116 | reg_val = &cntx->vector.vcsr; | |
117 | break; | |
118 | case KVM_REG_RISCV_VECTOR_CSR_REG(datap): | |
119 | default: | |
120 | return NULL; | |
121 | } | |
122 | } else if (reg_num <= KVM_REG_RISCV_VECTOR_REG(31)) { | |
123 | if (reg_size != vlenb) | |
124 | return NULL; | |
125 | reg_val = cntx->vector.datap | |
126 | + (reg_num - KVM_REG_RISCV_VECTOR_REG(0)) * vlenb; | |
127 | } else { | |
128 | return NULL; | |
129 | } | |
130 | ||
131 | return reg_val; | |
132 | } | |
133 | ||
134 | int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu, | |
135 | const struct kvm_one_reg *reg, | |
136 | unsigned long rtype) | |
137 | { | |
138 | unsigned long *isa = vcpu->arch.isa; | |
139 | unsigned long __user *uaddr = | |
140 | (unsigned long __user *)(unsigned long)reg->addr; | |
141 | unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | | |
142 | KVM_REG_SIZE_MASK | | |
143 | rtype); | |
144 | void *reg_val = NULL; | |
145 | size_t reg_size = KVM_REG_SIZE(reg->id); | |
146 | ||
147 | if (rtype == KVM_REG_RISCV_VECTOR && | |
148 | riscv_isa_extension_available(isa, v)) { | |
149 | reg_val = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size); | |
150 | } | |
151 | ||
152 | if (!reg_val) | |
153 | return -EINVAL; | |
154 | ||
155 | if (copy_to_user(uaddr, reg_val, reg_size)) | |
156 | return -EFAULT; | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
161 | int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu, | |
162 | const struct kvm_one_reg *reg, | |
163 | unsigned long rtype) | |
164 | { | |
165 | unsigned long *isa = vcpu->arch.isa; | |
166 | unsigned long __user *uaddr = | |
167 | (unsigned long __user *)(unsigned long)reg->addr; | |
168 | unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | | |
169 | KVM_REG_SIZE_MASK | | |
170 | rtype); | |
171 | void *reg_val = NULL; | |
172 | size_t reg_size = KVM_REG_SIZE(reg->id); | |
173 | ||
174 | if (rtype == KVM_REG_RISCV_VECTOR && | |
175 | riscv_isa_extension_available(isa, v)) { | |
176 | reg_val = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size); | |
177 | } | |
178 | ||
179 | if (!reg_val) | |
180 | return -EINVAL; | |
181 | ||
182 | if (copy_from_user(reg_val, uaddr, reg_size)) | |
183 | return -EFAULT; | |
184 | ||
185 | return 0; | |
186 | } |