1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * FF-A v1.0 proxy to filter out invalid memory-sharing SMC calls issued by
4 * the host. FF-A is a slightly more palatable abbreviation of "Arm Firmware
5 * Framework for Arm A-profile", which is specified by Arm in document
6 * number DEN0077.
7 *
8 * Copyright (C) 2022 - Google LLC
9 * Author: Andrew Walbran <qwandor@google.com>
10 *
11 * This driver hooks into the SMC trapping logic for the host and intercepts
12 * all calls falling within the FF-A range. Each call is either:
13 *
14 * - Forwarded on unmodified to the SPMD at EL3
15 * - Rejected as "unsupported"
16 * - Accompanied by a host stage-2 page-table check/update and reissued
17 *
18 * Consequently, any attempts by the host to make guest memory pages
19 * accessible to the secure world using FF-A will be detected either here
20 * (in the case that the memory is already owned by the guest) or during
21 * donation to the guest (in the case that the memory was previously shared
22 * with the secure world).
23 *
24 * To allow the rolling-back of page-table updates and FF-A calls in the
25 * event of failure, operations involving the RXTX buffers are locked for
26 * the duration and are therefore serialised.
27 */
28
29 #include <linux/arm-smccc.h>
30 #include <linux/arm_ffa.h>
31 #include <asm/kvm_pkvm.h>
32
33 #include <nvhe/ffa.h>
34 #include <nvhe/mem_protect.h>
35 #include <nvhe/memory.h>
36 #include <nvhe/trap_handler.h>
37 #include <nvhe/spinlock.h>
38
39 /*
40 * "ID value 0 must be returned at the Non-secure physical FF-A instance"
41 * We share this ID with the host.
42 */
43 #define HOST_FFA_ID 0
44
45 /*
46 * A buffer to hold the maximum descriptor size we can see from the host,
47 * which is required when the SPMD returns a fragmented FFA_MEM_RETRIEVE_RESP
48 * when resolving the handle on the reclaim path.
49 */
50 struct kvm_ffa_descriptor_buffer {
51 void *buf;
52 size_t len;
53 };
54
55 static struct kvm_ffa_descriptor_buffer ffa_desc_buf;
56
57 struct kvm_ffa_buffers {
58 hyp_spinlock_t lock;
59 void *tx;
60 void *rx;
61 };
62
63 /*
64 * Note that we don't currently lock these buffers explicitly, instead
65 * relying on the locking of the host FFA buffers as we only have one
66 * client.
67 */
68 static struct kvm_ffa_buffers hyp_buffers;
69 static struct kvm_ffa_buffers host_buffers;
70
ffa_to_smccc_error(struct arm_smccc_res * res,u64 ffa_errno)71 static void ffa_to_smccc_error(struct arm_smccc_res *res, u64 ffa_errno)
72 {
73 *res = (struct arm_smccc_res) {
74 .a0 = FFA_ERROR,
75 .a2 = ffa_errno,
76 };
77 }
78
ffa_to_smccc_res_prop(struct arm_smccc_res * res,int ret,u64 prop)79 static void ffa_to_smccc_res_prop(struct arm_smccc_res *res, int ret, u64 prop)
80 {
81 if (ret == FFA_RET_SUCCESS) {
82 *res = (struct arm_smccc_res) { .a0 = FFA_SUCCESS,
83 .a2 = prop };
84 } else {
85 ffa_to_smccc_error(res, ret);
86 }
87 }
88
ffa_to_smccc_res(struct arm_smccc_res * res,int ret)89 static void ffa_to_smccc_res(struct arm_smccc_res *res, int ret)
90 {
91 ffa_to_smccc_res_prop(res, ret, 0);
92 }
93
ffa_set_retval(struct kvm_cpu_context * ctxt,struct arm_smccc_res * res)94 static void ffa_set_retval(struct kvm_cpu_context *ctxt,
95 struct arm_smccc_res *res)
96 {
97 cpu_reg(ctxt, 0) = res->a0;
98 cpu_reg(ctxt, 1) = res->a1;
99 cpu_reg(ctxt, 2) = res->a2;
100 cpu_reg(ctxt, 3) = res->a3;
101 }
102
is_ffa_call(u64 func_id)103 static bool is_ffa_call(u64 func_id)
104 {
105 return ARM_SMCCC_IS_FAST_CALL(func_id) &&
106 ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
107 ARM_SMCCC_FUNC_NUM(func_id) >= FFA_MIN_FUNC_NUM &&
108 ARM_SMCCC_FUNC_NUM(func_id) <= FFA_MAX_FUNC_NUM;
109 }
110
ffa_map_hyp_buffers(u64 ffa_page_count)111 static int ffa_map_hyp_buffers(u64 ffa_page_count)
112 {
113 struct arm_smccc_res res;
114
115 arm_smccc_1_1_smc(FFA_FN64_RXTX_MAP,
116 hyp_virt_to_phys(hyp_buffers.tx),
117 hyp_virt_to_phys(hyp_buffers.rx),
118 ffa_page_count,
119 0, 0, 0, 0,
120 &res);
121
122 return res.a0 == FFA_SUCCESS ? FFA_RET_SUCCESS : res.a2;
123 }
124
ffa_unmap_hyp_buffers(void)125 static int ffa_unmap_hyp_buffers(void)
126 {
127 struct arm_smccc_res res;
128
129 arm_smccc_1_1_smc(FFA_RXTX_UNMAP,
130 HOST_FFA_ID,
131 0, 0, 0, 0, 0, 0,
132 &res);
133
134 return res.a0 == FFA_SUCCESS ? FFA_RET_SUCCESS : res.a2;
135 }
136
ffa_mem_frag_tx(struct arm_smccc_res * res,u32 handle_lo,u32 handle_hi,u32 fraglen,u32 endpoint_id)137 static void ffa_mem_frag_tx(struct arm_smccc_res *res, u32 handle_lo,
138 u32 handle_hi, u32 fraglen, u32 endpoint_id)
139 {
140 arm_smccc_1_1_smc(FFA_MEM_FRAG_TX,
141 handle_lo, handle_hi, fraglen, endpoint_id,
142 0, 0, 0,
143 res);
144 }
145
ffa_mem_frag_rx(struct arm_smccc_res * res,u32 handle_lo,u32 handle_hi,u32 fragoff)146 static void ffa_mem_frag_rx(struct arm_smccc_res *res, u32 handle_lo,
147 u32 handle_hi, u32 fragoff)
148 {
149 arm_smccc_1_1_smc(FFA_MEM_FRAG_RX,
150 handle_lo, handle_hi, fragoff, HOST_FFA_ID,
151 0, 0, 0,
152 res);
153 }
154
ffa_mem_xfer(struct arm_smccc_res * res,u64 func_id,u32 len,u32 fraglen)155 static void ffa_mem_xfer(struct arm_smccc_res *res, u64 func_id, u32 len,
156 u32 fraglen)
157 {
158 arm_smccc_1_1_smc(func_id, len, fraglen,
159 0, 0, 0, 0, 0,
160 res);
161 }
162
ffa_mem_reclaim(struct arm_smccc_res * res,u32 handle_lo,u32 handle_hi,u32 flags)163 static void ffa_mem_reclaim(struct arm_smccc_res *res, u32 handle_lo,
164 u32 handle_hi, u32 flags)
165 {
166 arm_smccc_1_1_smc(FFA_MEM_RECLAIM,
167 handle_lo, handle_hi, flags,
168 0, 0, 0, 0,
169 res);
170 }
171
ffa_retrieve_req(struct arm_smccc_res * res,u32 len)172 static void ffa_retrieve_req(struct arm_smccc_res *res, u32 len)
173 {
174 arm_smccc_1_1_smc(FFA_FN64_MEM_RETRIEVE_REQ,
175 len, len,
176 0, 0, 0, 0, 0,
177 res);
178 }
179
do_ffa_rxtx_map(struct arm_smccc_res * res,struct kvm_cpu_context * ctxt)180 static void do_ffa_rxtx_map(struct arm_smccc_res *res,
181 struct kvm_cpu_context *ctxt)
182 {
183 DECLARE_REG(phys_addr_t, tx, ctxt, 1);
184 DECLARE_REG(phys_addr_t, rx, ctxt, 2);
185 DECLARE_REG(u32, npages, ctxt, 3);
186 int ret = 0;
187 void *rx_virt, *tx_virt;
188
189 if (npages != (KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) / FFA_PAGE_SIZE) {
190 ret = FFA_RET_INVALID_PARAMETERS;
191 goto out;
192 }
193
194 if (!PAGE_ALIGNED(tx) || !PAGE_ALIGNED(rx)) {
195 ret = FFA_RET_INVALID_PARAMETERS;
196 goto out;
197 }
198
199 hyp_spin_lock(&host_buffers.lock);
200 if (host_buffers.tx) {
201 ret = FFA_RET_DENIED;
202 goto out_unlock;
203 }
204
205 /*
206 * Map our hypervisor buffers into the SPMD before mapping and
207 * pinning the host buffers in our own address space.
208 */
209 ret = ffa_map_hyp_buffers(npages);
210 if (ret)
211 goto out_unlock;
212
213 ret = __pkvm_host_share_hyp(hyp_phys_to_pfn(tx));
214 if (ret) {
215 ret = FFA_RET_INVALID_PARAMETERS;
216 goto err_unmap;
217 }
218
219 ret = __pkvm_host_share_hyp(hyp_phys_to_pfn(rx));
220 if (ret) {
221 ret = FFA_RET_INVALID_PARAMETERS;
222 goto err_unshare_tx;
223 }
224
225 tx_virt = hyp_phys_to_virt(tx);
226 ret = hyp_pin_shared_mem(tx_virt, tx_virt + 1);
227 if (ret) {
228 ret = FFA_RET_INVALID_PARAMETERS;
229 goto err_unshare_rx;
230 }
231
232 rx_virt = hyp_phys_to_virt(rx);
233 ret = hyp_pin_shared_mem(rx_virt, rx_virt + 1);
234 if (ret) {
235 ret = FFA_RET_INVALID_PARAMETERS;
236 goto err_unpin_tx;
237 }
238
239 host_buffers.tx = tx_virt;
240 host_buffers.rx = rx_virt;
241
242 out_unlock:
243 hyp_spin_unlock(&host_buffers.lock);
244 out:
245 ffa_to_smccc_res(res, ret);
246 return;
247
248 err_unpin_tx:
249 hyp_unpin_shared_mem(tx_virt, tx_virt + 1);
250 err_unshare_rx:
251 __pkvm_host_unshare_hyp(hyp_phys_to_pfn(rx));
252 err_unshare_tx:
253 __pkvm_host_unshare_hyp(hyp_phys_to_pfn(tx));
254 err_unmap:
255 ffa_unmap_hyp_buffers();
256 goto out_unlock;
257 }
258
do_ffa_rxtx_unmap(struct arm_smccc_res * res,struct kvm_cpu_context * ctxt)259 static void do_ffa_rxtx_unmap(struct arm_smccc_res *res,
260 struct kvm_cpu_context *ctxt)
261 {
262 DECLARE_REG(u32, id, ctxt, 1);
263 int ret = 0;
264
265 if (id != HOST_FFA_ID) {
266 ret = FFA_RET_INVALID_PARAMETERS;
267 goto out;
268 }
269
270 hyp_spin_lock(&host_buffers.lock);
271 if (!host_buffers.tx) {
272 ret = FFA_RET_INVALID_PARAMETERS;
273 goto out_unlock;
274 }
275
276 hyp_unpin_shared_mem(host_buffers.tx, host_buffers.tx + 1);
277 WARN_ON(__pkvm_host_unshare_hyp(hyp_virt_to_pfn(host_buffers.tx)));
278 host_buffers.tx = NULL;
279
280 hyp_unpin_shared_mem(host_buffers.rx, host_buffers.rx + 1);
281 WARN_ON(__pkvm_host_unshare_hyp(hyp_virt_to_pfn(host_buffers.rx)));
282 host_buffers.rx = NULL;
283
284 ffa_unmap_hyp_buffers();
285
286 out_unlock:
287 hyp_spin_unlock(&host_buffers.lock);
288 out:
289 ffa_to_smccc_res(res, ret);
290 }
291
__ffa_host_share_ranges(struct ffa_mem_region_addr_range * ranges,u32 nranges)292 static u32 __ffa_host_share_ranges(struct ffa_mem_region_addr_range *ranges,
293 u32 nranges)
294 {
295 u32 i;
296
297 for (i = 0; i < nranges; ++i) {
298 struct ffa_mem_region_addr_range *range = &ranges[i];
299 u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE;
300 u64 pfn = hyp_phys_to_pfn(range->address);
301
302 if (!PAGE_ALIGNED(sz))
303 break;
304
305 if (__pkvm_host_share_ffa(pfn, sz / PAGE_SIZE))
306 break;
307 }
308
309 return i;
310 }
311
__ffa_host_unshare_ranges(struct ffa_mem_region_addr_range * ranges,u32 nranges)312 static u32 __ffa_host_unshare_ranges(struct ffa_mem_region_addr_range *ranges,
313 u32 nranges)
314 {
315 u32 i;
316
317 for (i = 0; i < nranges; ++i) {
318 struct ffa_mem_region_addr_range *range = &ranges[i];
319 u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE;
320 u64 pfn = hyp_phys_to_pfn(range->address);
321
322 if (!PAGE_ALIGNED(sz))
323 break;
324
325 if (__pkvm_host_unshare_ffa(pfn, sz / PAGE_SIZE))
326 break;
327 }
328
329 return i;
330 }
331
ffa_host_share_ranges(struct ffa_mem_region_addr_range * ranges,u32 nranges)332 static int ffa_host_share_ranges(struct ffa_mem_region_addr_range *ranges,
333 u32 nranges)
334 {
335 u32 nshared = __ffa_host_share_ranges(ranges, nranges);
336 int ret = 0;
337
338 if (nshared != nranges) {
339 WARN_ON(__ffa_host_unshare_ranges(ranges, nshared) != nshared);
340 ret = FFA_RET_DENIED;
341 }
342
343 return ret;
344 }
345
ffa_host_unshare_ranges(struct ffa_mem_region_addr_range * ranges,u32 nranges)346 static int ffa_host_unshare_ranges(struct ffa_mem_region_addr_range *ranges,
347 u32 nranges)
348 {
349 u32 nunshared = __ffa_host_unshare_ranges(ranges, nranges);
350 int ret = 0;
351
352 if (nunshared != nranges) {
353 WARN_ON(__ffa_host_share_ranges(ranges, nunshared) != nunshared);
354 ret = FFA_RET_DENIED;
355 }
356
357 return ret;
358 }
359
do_ffa_mem_frag_tx(struct arm_smccc_res * res,struct kvm_cpu_context * ctxt)360 static void do_ffa_mem_frag_tx(struct arm_smccc_res *res,
361 struct kvm_cpu_context *ctxt)
362 {
363 DECLARE_REG(u32, handle_lo, ctxt, 1);
364 DECLARE_REG(u32, handle_hi, ctxt, 2);
365 DECLARE_REG(u32, fraglen, ctxt, 3);
366 DECLARE_REG(u32, endpoint_id, ctxt, 4);
367 struct ffa_mem_region_addr_range *buf;
368 int ret = FFA_RET_INVALID_PARAMETERS;
369 u32 nr_ranges;
370
371 if (fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE)
372 goto out;
373
374 if (fraglen % sizeof(*buf))
375 goto out;
376
377 hyp_spin_lock(&host_buffers.lock);
378 if (!host_buffers.tx)
379 goto out_unlock;
380
381 buf = hyp_buffers.tx;
382 memcpy(buf, host_buffers.tx, fraglen);
383 nr_ranges = fraglen / sizeof(*buf);
384
385 ret = ffa_host_share_ranges(buf, nr_ranges);
386 if (ret) {
387 /*
388 * We're effectively aborting the transaction, so we need
389 * to restore the global state back to what it was prior to
390 * transmission of the first fragment.
391 */
392 ffa_mem_reclaim(res, handle_lo, handle_hi, 0);
393 WARN_ON(res->a0 != FFA_SUCCESS);
394 goto out_unlock;
395 }
396
397 ffa_mem_frag_tx(res, handle_lo, handle_hi, fraglen, endpoint_id);
398 if (res->a0 != FFA_SUCCESS && res->a0 != FFA_MEM_FRAG_RX)
399 WARN_ON(ffa_host_unshare_ranges(buf, nr_ranges));
400
401 out_unlock:
402 hyp_spin_unlock(&host_buffers.lock);
403 out:
404 if (ret)
405 ffa_to_smccc_res(res, ret);
406
407 /*
408 * If for any reason this did not succeed, we're in trouble as we have
409 * now lost the content of the previous fragments and we can't rollback
410 * the host stage-2 changes. The pages previously marked as shared will
411 * remain stuck in that state forever, hence preventing the host from
412 * sharing/donating them again and may possibly lead to subsequent
413 * failures, but this will not compromise confidentiality.
414 */
415 return;
416 }
417
do_ffa_mem_xfer(const u64 func_id,struct arm_smccc_res * res,struct kvm_cpu_context * ctxt)418 static __always_inline void do_ffa_mem_xfer(const u64 func_id,
419 struct arm_smccc_res *res,
420 struct kvm_cpu_context *ctxt)
421 {
422 DECLARE_REG(u32, len, ctxt, 1);
423 DECLARE_REG(u32, fraglen, ctxt, 2);
424 DECLARE_REG(u64, addr_mbz, ctxt, 3);
425 DECLARE_REG(u32, npages_mbz, ctxt, 4);
426 struct ffa_composite_mem_region *reg;
427 struct ffa_mem_region *buf;
428 u32 offset, nr_ranges;
429 int ret = 0;
430
431 BUILD_BUG_ON(func_id != FFA_FN64_MEM_SHARE &&
432 func_id != FFA_FN64_MEM_LEND);
433
434 if (addr_mbz || npages_mbz || fraglen > len ||
435 fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) {
436 ret = FFA_RET_INVALID_PARAMETERS;
437 goto out;
438 }
439
440 if (fraglen < sizeof(struct ffa_mem_region) +
441 sizeof(struct ffa_mem_region_attributes)) {
442 ret = FFA_RET_INVALID_PARAMETERS;
443 goto out;
444 }
445
446 hyp_spin_lock(&host_buffers.lock);
447 if (!host_buffers.tx) {
448 ret = FFA_RET_INVALID_PARAMETERS;
449 goto out_unlock;
450 }
451
452 buf = hyp_buffers.tx;
453 memcpy(buf, host_buffers.tx, fraglen);
454
455 offset = buf->ep_mem_access[0].composite_off;
456 if (!offset || buf->ep_count != 1 || buf->sender_id != HOST_FFA_ID) {
457 ret = FFA_RET_INVALID_PARAMETERS;
458 goto out_unlock;
459 }
460
461 if (fraglen < offset + sizeof(struct ffa_composite_mem_region)) {
462 ret = FFA_RET_INVALID_PARAMETERS;
463 goto out_unlock;
464 }
465
466 reg = (void *)buf + offset;
467 nr_ranges = ((void *)buf + fraglen) - (void *)reg->constituents;
468 if (nr_ranges % sizeof(reg->constituents[0])) {
469 ret = FFA_RET_INVALID_PARAMETERS;
470 goto out_unlock;
471 }
472
473 nr_ranges /= sizeof(reg->constituents[0]);
474 ret = ffa_host_share_ranges(reg->constituents, nr_ranges);
475 if (ret)
476 goto out_unlock;
477
478 ffa_mem_xfer(res, func_id, len, fraglen);
479 if (fraglen != len) {
480 if (res->a0 != FFA_MEM_FRAG_RX)
481 goto err_unshare;
482
483 if (res->a3 != fraglen)
484 goto err_unshare;
485 } else if (res->a0 != FFA_SUCCESS) {
486 goto err_unshare;
487 }
488
489 out_unlock:
490 hyp_spin_unlock(&host_buffers.lock);
491 out:
492 if (ret)
493 ffa_to_smccc_res(res, ret);
494 return;
495
496 err_unshare:
497 WARN_ON(ffa_host_unshare_ranges(reg->constituents, nr_ranges));
498 goto out_unlock;
499 }
500
do_ffa_mem_reclaim(struct arm_smccc_res * res,struct kvm_cpu_context * ctxt)501 static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
502 struct kvm_cpu_context *ctxt)
503 {
504 DECLARE_REG(u32, handle_lo, ctxt, 1);
505 DECLARE_REG(u32, handle_hi, ctxt, 2);
506 DECLARE_REG(u32, flags, ctxt, 3);
507 struct ffa_composite_mem_region *reg;
508 u32 offset, len, fraglen, fragoff;
509 struct ffa_mem_region *buf;
510 int ret = 0;
511 u64 handle;
512
513 handle = PACK_HANDLE(handle_lo, handle_hi);
514
515 hyp_spin_lock(&host_buffers.lock);
516
517 buf = hyp_buffers.tx;
518 *buf = (struct ffa_mem_region) {
519 .sender_id = HOST_FFA_ID,
520 .handle = handle,
521 };
522
523 ffa_retrieve_req(res, sizeof(*buf));
524 buf = hyp_buffers.rx;
525 if (res->a0 != FFA_MEM_RETRIEVE_RESP)
526 goto out_unlock;
527
528 len = res->a1;
529 fraglen = res->a2;
530
531 offset = buf->ep_mem_access[0].composite_off;
532 /*
533 * We can trust the SPMD to get this right, but let's at least
534 * check that we end up with something that doesn't look _completely_
535 * bogus.
536 */
537 if (WARN_ON(offset > len ||
538 fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE)) {
539 ret = FFA_RET_ABORTED;
540 goto out_unlock;
541 }
542
543 if (len > ffa_desc_buf.len) {
544 ret = FFA_RET_NO_MEMORY;
545 goto out_unlock;
546 }
547
548 buf = ffa_desc_buf.buf;
549 memcpy(buf, hyp_buffers.rx, fraglen);
550
551 for (fragoff = fraglen; fragoff < len; fragoff += fraglen) {
552 ffa_mem_frag_rx(res, handle_lo, handle_hi, fragoff);
553 if (res->a0 != FFA_MEM_FRAG_TX) {
554 ret = FFA_RET_INVALID_PARAMETERS;
555 goto out_unlock;
556 }
557
558 fraglen = res->a3;
559 memcpy((void *)buf + fragoff, hyp_buffers.rx, fraglen);
560 }
561
562 ffa_mem_reclaim(res, handle_lo, handle_hi, flags);
563 if (res->a0 != FFA_SUCCESS)
564 goto out_unlock;
565
566 reg = (void *)buf + offset;
567 /* If the SPMD was happy, then we should be too. */
568 WARN_ON(ffa_host_unshare_ranges(reg->constituents,
569 reg->addr_range_cnt));
570 out_unlock:
571 hyp_spin_unlock(&host_buffers.lock);
572
573 if (ret)
574 ffa_to_smccc_res(res, ret);
575 }
576
577 /*
578 * Is a given FFA function supported, either by forwarding on directly
579 * or by handling at EL2?
580 */
ffa_call_supported(u64 func_id)581 static bool ffa_call_supported(u64 func_id)
582 {
583 switch (func_id) {
584 /* Unsupported memory management calls */
585 case FFA_FN64_MEM_RETRIEVE_REQ:
586 case FFA_MEM_RETRIEVE_RESP:
587 case FFA_MEM_RELINQUISH:
588 case FFA_MEM_OP_PAUSE:
589 case FFA_MEM_OP_RESUME:
590 case FFA_MEM_FRAG_RX:
591 case FFA_FN64_MEM_DONATE:
592 /* Indirect message passing via RX/TX buffers */
593 case FFA_MSG_SEND:
594 case FFA_MSG_POLL:
595 case FFA_MSG_WAIT:
596 /* 32-bit variants of 64-bit calls */
597 case FFA_MSG_SEND_DIRECT_REQ:
598 case FFA_MSG_SEND_DIRECT_RESP:
599 case FFA_RXTX_MAP:
600 case FFA_MEM_DONATE:
601 case FFA_MEM_RETRIEVE_REQ:
602 return false;
603 }
604
605 return true;
606 }
607
do_ffa_features(struct arm_smccc_res * res,struct kvm_cpu_context * ctxt)608 static bool do_ffa_features(struct arm_smccc_res *res,
609 struct kvm_cpu_context *ctxt)
610 {
611 DECLARE_REG(u32, id, ctxt, 1);
612 u64 prop = 0;
613 int ret = 0;
614
615 if (!ffa_call_supported(id)) {
616 ret = FFA_RET_NOT_SUPPORTED;
617 goto out_handled;
618 }
619
620 switch (id) {
621 case FFA_MEM_SHARE:
622 case FFA_FN64_MEM_SHARE:
623 case FFA_MEM_LEND:
624 case FFA_FN64_MEM_LEND:
625 ret = FFA_RET_SUCCESS;
626 prop = 0; /* No support for dynamic buffers */
627 goto out_handled;
628 default:
629 return false;
630 }
631
632 out_handled:
633 ffa_to_smccc_res_prop(res, ret, prop);
634 return true;
635 }
636
kvm_host_ffa_handler(struct kvm_cpu_context * host_ctxt,u32 func_id)637 bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
638 {
639 struct arm_smccc_res res;
640
641 /*
642 * There's no way we can tell what a non-standard SMC call might
643 * be up to. Ideally, we would terminate these here and return
644 * an error to the host, but sadly devices make use of custom
645 * firmware calls for things like power management, debugging,
646 * RNG access and crash reporting.
647 *
648 * Given that the architecture requires us to trust EL3 anyway,
649 * we forward unrecognised calls on under the assumption that
650 * the firmware doesn't expose a mechanism to access arbitrary
651 * non-secure memory. Short of a per-device table of SMCs, this
652 * is the best we can do.
653 */
654 if (!is_ffa_call(func_id))
655 return false;
656
657 switch (func_id) {
658 case FFA_FEATURES:
659 if (!do_ffa_features(&res, host_ctxt))
660 return false;
661 goto out_handled;
662 /* Memory management */
663 case FFA_FN64_RXTX_MAP:
664 do_ffa_rxtx_map(&res, host_ctxt);
665 goto out_handled;
666 case FFA_RXTX_UNMAP:
667 do_ffa_rxtx_unmap(&res, host_ctxt);
668 goto out_handled;
669 case FFA_MEM_SHARE:
670 case FFA_FN64_MEM_SHARE:
671 do_ffa_mem_xfer(FFA_FN64_MEM_SHARE, &res, host_ctxt);
672 goto out_handled;
673 case FFA_MEM_RECLAIM:
674 do_ffa_mem_reclaim(&res, host_ctxt);
675 goto out_handled;
676 case FFA_MEM_LEND:
677 case FFA_FN64_MEM_LEND:
678 do_ffa_mem_xfer(FFA_FN64_MEM_LEND, &res, host_ctxt);
679 goto out_handled;
680 case FFA_MEM_FRAG_TX:
681 do_ffa_mem_frag_tx(&res, host_ctxt);
682 goto out_handled;
683 }
684
685 if (ffa_call_supported(func_id))
686 return false; /* Pass through */
687
688 ffa_to_smccc_error(&res, FFA_RET_NOT_SUPPORTED);
689 out_handled:
690 ffa_set_retval(host_ctxt, &res);
691 return true;
692 }
693
hyp_ffa_init(void * pages)694 int hyp_ffa_init(void *pages)
695 {
696 struct arm_smccc_res res;
697 size_t min_rxtx_sz;
698 void *tx, *rx;
699
700 if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2)
701 return 0;
702
703 arm_smccc_1_1_smc(FFA_VERSION, FFA_VERSION_1_0, 0, 0, 0, 0, 0, 0, &res);
704 if (res.a0 == FFA_RET_NOT_SUPPORTED)
705 return 0;
706
707 /*
708 * Firmware returns the maximum supported version of the FF-A
709 * implementation. Check that the returned version is
710 * backwards-compatible with the hyp according to the rules in DEN0077A
711 * v1.1 REL0 13.2.1.
712 *
713 * Of course, things are never simple when dealing with firmware. v1.1
714 * broke ABI with v1.0 on several structures, which is itself
715 * incompatible with the aforementioned versioning scheme. The
716 * expectation is that v1.x implementations that do not support the v1.0
717 * ABI return NOT_SUPPORTED rather than a version number, according to
718 * DEN0077A v1.1 REL0 18.6.4.
719 */
720 if (FFA_MAJOR_VERSION(res.a0) != 1)
721 return -EOPNOTSUPP;
722
723 arm_smccc_1_1_smc(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0, &res);
724 if (res.a0 != FFA_SUCCESS)
725 return -EOPNOTSUPP;
726
727 if (res.a2 != HOST_FFA_ID)
728 return -EINVAL;
729
730 arm_smccc_1_1_smc(FFA_FEATURES, FFA_FN64_RXTX_MAP,
731 0, 0, 0, 0, 0, 0, &res);
732 if (res.a0 != FFA_SUCCESS)
733 return -EOPNOTSUPP;
734
735 switch (res.a2) {
736 case FFA_FEAT_RXTX_MIN_SZ_4K:
737 min_rxtx_sz = SZ_4K;
738 break;
739 case FFA_FEAT_RXTX_MIN_SZ_16K:
740 min_rxtx_sz = SZ_16K;
741 break;
742 case FFA_FEAT_RXTX_MIN_SZ_64K:
743 min_rxtx_sz = SZ_64K;
744 break;
745 default:
746 return -EINVAL;
747 }
748
749 if (min_rxtx_sz > PAGE_SIZE)
750 return -EOPNOTSUPP;
751
752 tx = pages;
753 pages += KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE;
754 rx = pages;
755 pages += KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE;
756
757 ffa_desc_buf = (struct kvm_ffa_descriptor_buffer) {
758 .buf = pages,
759 .len = PAGE_SIZE *
760 (hyp_ffa_proxy_pages() - (2 * KVM_FFA_MBOX_NR_PAGES)),
761 };
762
763 hyp_buffers = (struct kvm_ffa_buffers) {
764 .lock = __HYP_SPIN_LOCK_UNLOCKED,
765 .tx = tx,
766 .rx = rx,
767 };
768
769 host_buffers = (struct kvm_ffa_buffers) {
770 .lock = __HYP_SPIN_LOCK_UNLOCKED,
771 };
772
773 return 0;
774 }
775