blob: 097a8d97d7d7c0ec5870e16fd105f65bbe70015e [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <buffer.h>
7#include <granule.h>
8#include <realm.h>
AlexeiFedorov5b186ad2023-04-26 14:43:18 +01009#include <rsi-handler.h>
AlexeiFedorovee2fc822023-10-31 14:54:39 +000010#include <rsi-host-call.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000011#include <smc-rsi.h>
12#include <status.h>
13#include <string.h>
14
15/*
16 * If the RIPAS of the target IPA is empty then return value is RSI_ERROR_INPUT.
17 *
18 * If the RTT walk fails then:
19 * - @rsi_walk_result.abort is true and @rsi_walk_result.rtt_level is the
20 * last level reached by the walk.
21 * - Return value is RSI_SUCCESS.
22 *
23 * If the RTT walk succeeds then:
AlexeiFedorov52912a62023-07-24 12:28:47 +010024 * - If @rec_exit is not NULL and @rec_enter is NULL, then copy host call
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000025 * arguments from host call data structure (in Realm memory) to @rec_exit.
AlexeiFedorov52912a62023-07-24 12:28:47 +010026 * - If @rec_exit is NULL and @rec_enter is not NULL, then copy host call
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000027 * results to host call data structure (in Realm memory).
Soby Mathewb4c6df42022-11-09 11:13:29 +000028 * - Return value is RSI_SUCCESS.
29 */
AlexeiFedorov97844202023-04-27 15:17:35 +010030static void do_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
AlexeiFedorov52912a62023-07-24 12:28:47 +010031 struct rmi_rec_enter *rec_enter,
AlexeiFedorov97844202023-04-27 15:17:35 +010032 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +000033{
34 enum s2_walk_status walk_status;
35 struct s2_walk_result walk_result;
36 unsigned long ipa = rec->regs[1];
37 unsigned long page_ipa;
Soby Mathewb4c6df42022-11-09 11:13:29 +000038 struct granule *gr;
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010039 uintptr_t data;
Soby Mathewb4c6df42022-11-09 11:13:29 +000040 struct rsi_host_call *host_call;
41 unsigned int i;
Soby Mathewb4c6df42022-11-09 11:13:29 +000042
43 assert(addr_in_rec_par(rec, ipa));
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000044
AlexeiFedorov52912a62023-07-24 12:28:47 +010045 /* Only 'rec_enter' or 'rec_exit' should be set */
46 assert((rec_enter != NULL) != (rec_exit != NULL));
Soby Mathewb4c6df42022-11-09 11:13:29 +000047
Soby Mathewb4c6df42022-11-09 11:13:29 +000048 page_ipa = ipa & GRANULE_MASK;
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +010049 walk_status = realm_ipa_to_pa(rec, page_ipa, &walk_result);
Soby Mathewb4c6df42022-11-09 11:13:29 +000050
51 switch (walk_status) {
52 case WALK_SUCCESS:
53 break;
54 case WALK_FAIL:
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +010055 if (walk_result.ripas_val == RIPAS_EMPTY) {
AlexeiFedorov97844202023-04-27 15:17:35 +010056 res->smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +000057 } else {
AlexeiFedorov97844202023-04-27 15:17:35 +010058 res->action = STAGE_2_TRANSLATION_FAULT;
59 res->rtt_level = walk_result.rtt_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +000060 }
AlexeiFedorov97844202023-04-27 15:17:35 +010061 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +000062 case WALK_INVALID_PARAMS:
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010063 default:
Soby Mathewb4c6df42022-11-09 11:13:29 +000064 assert(false);
65 break;
66 }
67
68 /* Map Realm data granule to RMM address space */
69 gr = find_granule(walk_result.pa);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010070 data = (uintptr_t)granule_map(gr, SLOT_RSI_CALL);
71 assert(data != 0UL);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +010072
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010073 host_call = (struct rsi_host_call *)(data + ipa - page_ipa);
Soby Mathewb4c6df42022-11-09 11:13:29 +000074
75 if (rec_exit != NULL) {
76 /* Copy host call arguments to REC exit data structure */
77 rec_exit->imm = host_call->imm;
78 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
79 rec_exit->gprs[i] = host_call->gprs[i];
80 }
AlexeiFedorov97844202023-04-27 15:17:35 +010081
82 /* Record that a host call is pending */
83 rec->host_call = true;
84
85 /*
86 * Notify the Host.
87 * Leave REC registers unchanged,
88 * these will be read and updated by complete_rsi_host_call.
89 */
90 res->action = EXIT_TO_HOST;
91 rec_exit->exit_reason = RMI_EXIT_HOST_CALL;
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000092 } else {
Soby Mathewb4c6df42022-11-09 11:13:29 +000093 /* Copy host call results to host call data structure */
94 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
AlexeiFedorov52912a62023-07-24 12:28:47 +010095 host_call->gprs[i] = rec_enter->gprs[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +000096 }
AlexeiFedorov97844202023-04-27 15:17:35 +010097
98 rec->regs[0] = RSI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +000099 }
100
101 /* Unmap Realm data granule */
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100102 buffer_unmap((void *)data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000103
104 /* Unlock last level RTT */
105 granule_unlock(walk_result.llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000106}
107
AlexeiFedorov97844202023-04-27 15:17:35 +0100108void handle_rsi_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
109 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000110{
Soby Mathewb4c6df42022-11-09 11:13:29 +0000111 unsigned long ipa = rec->regs[1];
112
AlexeiFedorov97844202023-04-27 15:17:35 +0100113 res->action = UPDATE_REC_RETURN_TO_REALM;
114
Soby Mathewb4c6df42022-11-09 11:13:29 +0000115 if (!ALIGNED(ipa, sizeof(struct rsi_host_call))) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100116 res->smc_res.x[0] = RSI_ERROR_INPUT;
117 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000118 }
119
120 if ((ipa / GRANULE_SIZE) !=
121 ((ipa + sizeof(struct rsi_host_call) - 1UL) / GRANULE_SIZE)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100122 res->smc_res.x[0] = RSI_ERROR_INPUT;
123 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000124 }
125
126 if (!addr_in_rec_par(rec, ipa)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100127 res->smc_res.x[0] = RSI_ERROR_INPUT;
128 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000129 }
130
AlexeiFedorov97844202023-04-27 15:17:35 +0100131 do_host_call(rec, rec_exit, NULL, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000132}
133
134struct rsi_walk_result complete_rsi_host_call(struct rec *rec,
AlexeiFedorov52912a62023-07-24 12:28:47 +0100135 struct rmi_rec_enter *rec_enter)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000136{
AlexeiFedorov6a4314e2023-10-20 15:40:14 +0100137 struct rsi_result res = { (enum rsi_action)0U };
AlexeiFedorov97844202023-04-27 15:17:35 +0100138 struct rsi_walk_result walk_res = { false, 0UL };
Soby Mathewb4c6df42022-11-09 11:13:29 +0000139
140 /*
141 * Do the necessary to walk the S2 RTTs and copy args from NS Host
142 * to the host call data structure. But it is possible for the
143 * RIPAS of the IPA to be EMPTY and hence this call can return
144 * RSI_ERROR_INPUT. In this case, we return RSI_SUCCESS to Realm
145 * and Realm may take an abort on accessing the IPA (depending on
146 * the RIPAS of IPA at that time). This is a situation which can be
147 * controlled from Realm and Realm should avoid this.
148 */
AlexeiFedorov52912a62023-07-24 12:28:47 +0100149 do_host_call(rec, NULL, rec_enter, &res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000150
AlexeiFedorov97844202023-04-27 15:17:35 +0100151 if (res.action == STAGE_2_TRANSLATION_FAULT) {
152 walk_res.abort = true;
153 walk_res.rtt_level = res.rtt_level;
154 }
155
156 return walk_res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000157}