blob: 53ebc7342af74ce599363a5b0d7a97ff0044040b [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>
Soby Mathewb4c6df42022-11-09 11:13:29 +000012#include <string.h>
13
14/*
15 * If the RIPAS of the target IPA is empty then return value is RSI_ERROR_INPUT.
16 *
17 * If the RTT walk fails then:
18 * - @rsi_walk_result.abort is true and @rsi_walk_result.rtt_level is the
19 * last level reached by the walk.
20 * - Return value is RSI_SUCCESS.
21 *
22 * If the RTT walk succeeds then:
AlexeiFedorov52912a62023-07-24 12:28:47 +010023 * - If @rec_exit is not NULL and @rec_enter is NULL, then copy host call
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000024 * arguments from host call data structure (in Realm memory) to @rec_exit.
AlexeiFedorov52912a62023-07-24 12:28:47 +010025 * - If @rec_exit is NULL and @rec_enter is not NULL, then copy host call
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000026 * results to host call data structure (in Realm memory).
Soby Mathewb4c6df42022-11-09 11:13:29 +000027 * - Return value is RSI_SUCCESS.
28 */
AlexeiFedorov97844202023-04-27 15:17:35 +010029static void do_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
AlexeiFedorov52912a62023-07-24 12:28:47 +010030 struct rmi_rec_enter *rec_enter,
AlexeiFedorov97844202023-04-27 15:17:35 +010031 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +000032{
33 enum s2_walk_status walk_status;
34 struct s2_walk_result walk_result;
35 unsigned long ipa = rec->regs[1];
36 unsigned long page_ipa;
Soby Mathewb4c6df42022-11-09 11:13:29 +000037 struct granule *gr;
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010038 uintptr_t data;
Soby Mathewb4c6df42022-11-09 11:13:29 +000039 struct rsi_host_call *host_call;
40 unsigned int i;
Soby Mathewb4c6df42022-11-09 11:13:29 +000041
42 assert(addr_in_rec_par(rec, ipa));
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000043
AlexeiFedorov52912a62023-07-24 12:28:47 +010044 /* Only 'rec_enter' or 'rec_exit' should be set */
45 assert((rec_enter != NULL) != (rec_exit != NULL));
Soby Mathewb4c6df42022-11-09 11:13:29 +000046
Soby Mathewb4c6df42022-11-09 11:13:29 +000047 page_ipa = ipa & GRANULE_MASK;
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +010048 walk_status = realm_ipa_to_pa(rec, page_ipa, &walk_result);
Soby Mathewb4c6df42022-11-09 11:13:29 +000049
50 switch (walk_status) {
51 case WALK_SUCCESS:
52 break;
53 case WALK_FAIL:
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +010054 if (walk_result.ripas_val == RIPAS_EMPTY) {
AlexeiFedorov97844202023-04-27 15:17:35 +010055 res->smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +000056 } else {
AlexeiFedorov97844202023-04-27 15:17:35 +010057 res->action = STAGE_2_TRANSLATION_FAULT;
58 res->rtt_level = walk_result.rtt_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +000059 }
AlexeiFedorov97844202023-04-27 15:17:35 +010060 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +000061 case WALK_INVALID_PARAMS:
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010062 default:
Soby Mathewb4c6df42022-11-09 11:13:29 +000063 assert(false);
64 break;
65 }
66
67 /* Map Realm data granule to RMM address space */
68 gr = find_granule(walk_result.pa);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +000069 data = (uintptr_t)buffer_granule_map(gr, SLOT_RSI_CALL);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010070 assert(data != 0UL);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +010071
AlexeiFedorov3f5d6272023-10-23 16:27:37 +010072 host_call = (struct rsi_host_call *)(data + ipa - page_ipa);
Soby Mathewb4c6df42022-11-09 11:13:29 +000073
74 if (rec_exit != NULL) {
75 /* Copy host call arguments to REC exit data structure */
76 rec_exit->imm = host_call->imm;
77 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
78 rec_exit->gprs[i] = host_call->gprs[i];
79 }
AlexeiFedorov97844202023-04-27 15:17:35 +010080
81 /* Record that a host call is pending */
82 rec->host_call = true;
83
84 /*
85 * Notify the Host.
86 * Leave REC registers unchanged,
87 * these will be read and updated by complete_rsi_host_call.
88 */
89 res->action = EXIT_TO_HOST;
90 rec_exit->exit_reason = RMI_EXIT_HOST_CALL;
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000091 } else {
Soby Mathewb4c6df42022-11-09 11:13:29 +000092 /* Copy host call results to host call data structure */
93 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
AlexeiFedorov52912a62023-07-24 12:28:47 +010094 host_call->gprs[i] = rec_enter->gprs[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +000095 }
AlexeiFedorov97844202023-04-27 15:17:35 +010096
97 rec->regs[0] = RSI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +000098 }
99
100 /* Unmap Realm data granule */
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100101 buffer_unmap((void *)data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000102
103 /* Unlock last level RTT */
104 granule_unlock(walk_result.llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000105}
106
AlexeiFedorov97844202023-04-27 15:17:35 +0100107void handle_rsi_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
108 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109{
Soby Mathewb4c6df42022-11-09 11:13:29 +0000110 unsigned long ipa = rec->regs[1];
111
AlexeiFedorov97844202023-04-27 15:17:35 +0100112 res->action = UPDATE_REC_RETURN_TO_REALM;
113
Soby Mathewb4c6df42022-11-09 11:13:29 +0000114 if (!ALIGNED(ipa, sizeof(struct rsi_host_call))) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100115 res->smc_res.x[0] = RSI_ERROR_INPUT;
116 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000117 }
118
119 if ((ipa / GRANULE_SIZE) !=
120 ((ipa + sizeof(struct rsi_host_call) - 1UL) / GRANULE_SIZE)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100121 res->smc_res.x[0] = RSI_ERROR_INPUT;
122 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000123 }
124
125 if (!addr_in_rec_par(rec, ipa)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100126 res->smc_res.x[0] = RSI_ERROR_INPUT;
127 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000128 }
129
AlexeiFedorov97844202023-04-27 15:17:35 +0100130 do_host_call(rec, rec_exit, NULL, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000131}
132
133struct rsi_walk_result complete_rsi_host_call(struct rec *rec,
AlexeiFedorov52912a62023-07-24 12:28:47 +0100134 struct rmi_rec_enter *rec_enter)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000135{
AlexeiFedorov6a4314e2023-10-20 15:40:14 +0100136 struct rsi_result res = { (enum rsi_action)0U };
AlexeiFedorov97844202023-04-27 15:17:35 +0100137 struct rsi_walk_result walk_res = { false, 0UL };
Soby Mathewb4c6df42022-11-09 11:13:29 +0000138
139 /*
140 * Do the necessary to walk the S2 RTTs and copy args from NS Host
141 * to the host call data structure. But it is possible for the
142 * RIPAS of the IPA to be EMPTY and hence this call can return
143 * RSI_ERROR_INPUT. In this case, we return RSI_SUCCESS to Realm
144 * and Realm may take an abort on accessing the IPA (depending on
145 * the RIPAS of IPA at that time). This is a situation which can be
146 * controlled from Realm and Realm should avoid this.
147 */
AlexeiFedorov52912a62023-07-24 12:28:47 +0100148 do_host_call(rec, NULL, rec_enter, &res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000149
AlexeiFedorov97844202023-04-27 15:17:35 +0100150 if (res.action == STAGE_2_TRANSLATION_FAULT) {
151 walk_res.abort = true;
152 walk_res.rtt_level = res.rtt_level;
153 }
154
155 return walk_res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000156}