1 /*
2  * Copyright (C) 2011. Freescale Inc. All rights reserved.
3  *
4  * Authors:
5  *    Alexander Graf <agraf@suse.de>
6  *    Paul Mackerras <paulus@samba.org>
7  *
8  * Description:
9  *
10  * Hypercall handling for running PAPR guests in PR KVM on Book 3S
11  * processors.
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License, version 2, as
15  * published by the Free Software Foundation.
16  */
17 
18 #include <linux/anon_inodes.h>
19 
20 #include <asm/uaccess.h>
21 #include <asm/kvm_ppc.h>
22 #include <asm/kvm_book3s.h>
23 
24 static unsigned long get_pteg_addr(struct kvm_vcpu *vcpu, long pte_index)
25 {
26 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
27 	unsigned long pteg_addr;
28 
29 	pte_index <<= 4;
30 	pte_index &= ((1 << ((vcpu_book3s->sdr1 & 0x1f) + 11)) - 1) << 7 | 0x70;
31 	pteg_addr = vcpu_book3s->sdr1 & 0xfffffffffffc0000ULL;
32 	pteg_addr |= pte_index;
33 
34 	return pteg_addr;
35 }
36 
37 static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
38 {
39 	long flags = kvmppc_get_gpr(vcpu, 4);
40 	long pte_index = kvmppc_get_gpr(vcpu, 5);
41 	unsigned long pteg[2 * 8];
42 	unsigned long pteg_addr, i, *hpte;
43 
44 	pte_index &= ~7UL;
45 	pteg_addr = get_pteg_addr(vcpu, pte_index);
46 
47 	copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
48 	hpte = pteg;
49 
50 	if (likely((flags & H_EXACT) == 0)) {
51 		pte_index &= ~7UL;
52 		for (i = 0; ; ++i) {
53 			if (i == 8)
54 				return H_PTEG_FULL;
55 			if ((*hpte & HPTE_V_VALID) == 0)
56 				break;
57 			hpte += 2;
58 		}
59 	} else {
60 		i = kvmppc_get_gpr(vcpu, 5) & 7UL;
61 		hpte += i * 2;
62 	}
63 
64 	hpte[0] = kvmppc_get_gpr(vcpu, 6);
65 	hpte[1] = kvmppc_get_gpr(vcpu, 7);
66 	copy_to_user((void __user *)pteg_addr, pteg, sizeof(pteg));
67 	kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
68 	kvmppc_set_gpr(vcpu, 4, pte_index | i);
69 
70 	return EMULATE_DONE;
71 }
72 
73 static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
74 {
75 	unsigned long flags= kvmppc_get_gpr(vcpu, 4);
76 	unsigned long pte_index = kvmppc_get_gpr(vcpu, 5);
77 	unsigned long avpn = kvmppc_get_gpr(vcpu, 6);
78 	unsigned long v = 0, pteg, rb;
79 	unsigned long pte[2];
80 
81 	pteg = get_pteg_addr(vcpu, pte_index);
82 	copy_from_user(pte, (void __user *)pteg, sizeof(pte));
83 
84 	if ((pte[0] & HPTE_V_VALID) == 0 ||
85 	    ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn) ||
86 	    ((flags & H_ANDCOND) && (pte[0] & avpn) != 0)) {
87 		kvmppc_set_gpr(vcpu, 3, H_NOT_FOUND);
88 		return EMULATE_DONE;
89 	}
90 
91 	copy_to_user((void __user *)pteg, &v, sizeof(v));
92 
93 	rb = compute_tlbie_rb(pte[0], pte[1], pte_index);
94 	vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
95 
96 	kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
97 	kvmppc_set_gpr(vcpu, 4, pte[0]);
98 	kvmppc_set_gpr(vcpu, 5, pte[1]);
99 
100 	return EMULATE_DONE;
101 }
102 
103 /* Request defs for kvmppc_h_pr_bulk_remove() */
104 #define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
105 #define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
106 #define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
107 #define   H_BULK_REMOVE_END            0xc000000000000000ULL
108 #define H_BULK_REMOVE_CODE             0x3000000000000000ULL
109 #define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
110 #define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
111 #define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
112 #define   H_BULK_REMOVE_HW             0x3000000000000000ULL
113 #define H_BULK_REMOVE_RC               0x0c00000000000000ULL
114 #define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
115 #define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
116 #define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
117 #define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
118 #define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
119 #define H_BULK_REMOVE_MAX_BATCH        4
120 
121 static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
122 {
123 	int i;
124 	int paramnr = 4;
125 	int ret = H_SUCCESS;
126 
127 	for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
128 		unsigned long tsh = kvmppc_get_gpr(vcpu, paramnr+(2*i));
129 		unsigned long tsl = kvmppc_get_gpr(vcpu, paramnr+(2*i)+1);
130 		unsigned long pteg, rb, flags;
131 		unsigned long pte[2];
132 		unsigned long v = 0;
133 
134 		if ((tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
135 			break; /* Exit success */
136 		} else if ((tsh & H_BULK_REMOVE_TYPE) !=
137 			   H_BULK_REMOVE_REQUEST) {
138 			ret = H_PARAMETER;
139 			break; /* Exit fail */
140 		}
141 
142 		tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
143 		tsh |= H_BULK_REMOVE_RESPONSE;
144 
145 		if ((tsh & H_BULK_REMOVE_ANDCOND) &&
146 		    (tsh & H_BULK_REMOVE_AVPN)) {
147 			tsh |= H_BULK_REMOVE_PARM;
148 			kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh);
149 			ret = H_PARAMETER;
150 			break; /* Exit fail */
151 		}
152 
153 		pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
154 		copy_from_user(pte, (void __user *)pteg, sizeof(pte));
155 
156 		/* tsl = AVPN */
157 		flags = (tsh & H_BULK_REMOVE_FLAGS) >> 26;
158 
159 		if ((pte[0] & HPTE_V_VALID) == 0 ||
160 		    ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != tsl) ||
161 		    ((flags & H_ANDCOND) && (pte[0] & tsl) != 0)) {
162 			tsh |= H_BULK_REMOVE_NOT_FOUND;
163 		} else {
164 			/* Splat the pteg in (userland) hpt */
165 			copy_to_user((void __user *)pteg, &v, sizeof(v));
166 
167 			rb = compute_tlbie_rb(pte[0], pte[1],
168 					      tsh & H_BULK_REMOVE_PTEX);
169 			vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
170 			tsh |= H_BULK_REMOVE_SUCCESS;
171 			tsh |= (pte[1] & (HPTE_R_C | HPTE_R_R)) << 43;
172 		}
173 		kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh);
174 	}
175 	kvmppc_set_gpr(vcpu, 3, ret);
176 
177 	return EMULATE_DONE;
178 }
179 
180 static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
181 {
182 	unsigned long flags = kvmppc_get_gpr(vcpu, 4);
183 	unsigned long pte_index = kvmppc_get_gpr(vcpu, 5);
184 	unsigned long avpn = kvmppc_get_gpr(vcpu, 6);
185 	unsigned long rb, pteg, r, v;
186 	unsigned long pte[2];
187 
188 	pteg = get_pteg_addr(vcpu, pte_index);
189 	copy_from_user(pte, (void __user *)pteg, sizeof(pte));
190 
191 	if ((pte[0] & HPTE_V_VALID) == 0 ||
192 	    ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn)) {
193 		kvmppc_set_gpr(vcpu, 3, H_NOT_FOUND);
194 		return EMULATE_DONE;
195 	}
196 
197 	v = pte[0];
198 	r = pte[1];
199 	r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_HI |
200 	       HPTE_R_KEY_LO);
201 	r |= (flags << 55) & HPTE_R_PP0;
202 	r |= (flags << 48) & HPTE_R_KEY_HI;
203 	r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
204 
205 	pte[1] = r;
206 
207 	rb = compute_tlbie_rb(v, r, pte_index);
208 	vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
209 	copy_to_user((void __user *)pteg, pte, sizeof(pte));
210 
211 	kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
212 
213 	return EMULATE_DONE;
214 }
215 
216 static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu)
217 {
218 	unsigned long liobn = kvmppc_get_gpr(vcpu, 4);
219 	unsigned long ioba = kvmppc_get_gpr(vcpu, 5);
220 	unsigned long tce = kvmppc_get_gpr(vcpu, 6);
221 	long rc;
222 
223 	rc = kvmppc_h_put_tce(vcpu, liobn, ioba, tce);
224 	if (rc == H_TOO_HARD)
225 		return EMULATE_FAIL;
226 	kvmppc_set_gpr(vcpu, 3, rc);
227 	return EMULATE_DONE;
228 }
229 
230 int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
231 {
232 	switch (cmd) {
233 	case H_ENTER:
234 		return kvmppc_h_pr_enter(vcpu);
235 	case H_REMOVE:
236 		return kvmppc_h_pr_remove(vcpu);
237 	case H_PROTECT:
238 		return kvmppc_h_pr_protect(vcpu);
239 	case H_BULK_REMOVE:
240 		return kvmppc_h_pr_bulk_remove(vcpu);
241 	case H_PUT_TCE:
242 		return kvmppc_h_pr_put_tce(vcpu);
243 	case H_CEDE:
244 		vcpu->arch.shared->msr |= MSR_EE;
245 		kvm_vcpu_block(vcpu);
246 		clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
247 		vcpu->stat.halt_wakeup++;
248 		return EMULATE_DONE;
249 	}
250 
251 	return EMULATE_FAIL;
252 }
253