blob: 0aa8da24d0fef0b450f47484a798072fcbc1d5c8 [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>
Soby Mathewb4c6df42022-11-09 11:13:29 +000010#include <smc-rsi.h>
11#include <status.h>
12#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:
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000023 * - If @rec_exit is not NULL and @rec_entry is NULL, then copy host call
24 * arguments from host call data structure (in Realm memory) to @rec_exit.
25 * - If @rec_exit is NULL and @rec_entry is not NULL, then copy host call
26 * 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,
30 struct rmi_rec_entry *rec_entry,
31 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;
38 unsigned char *data;
39 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
44 /* Only 'rec_entry' or 'rec_exit' should be set */
AlexeiFedorove7b7da02023-08-29 11:51:57 +010045 assert((rec_entry != 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:
62 assert(false);
63 break;
64 }
65
66 /* Map Realm data granule to RMM address space */
67 gr = find_granule(walk_result.pa);
68 data = (unsigned char *)granule_map(gr, SLOT_RSI_CALL);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +010069 assert(data != NULL);
70
Soby Mathewb4c6df42022-11-09 11:13:29 +000071 host_call = (struct rsi_host_call *)(data + (ipa - page_ipa));
72
73 if (rec_exit != NULL) {
74 /* Copy host call arguments to REC exit data structure */
75 rec_exit->imm = host_call->imm;
76 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
77 rec_exit->gprs[i] = host_call->gprs[i];
78 }
AlexeiFedorov97844202023-04-27 15:17:35 +010079
80 /* Record that a host call is pending */
81 rec->host_call = true;
82
83 /*
84 * Notify the Host.
85 * Leave REC registers unchanged,
86 * these will be read and updated by complete_rsi_host_call.
87 */
88 res->action = EXIT_TO_HOST;
89 rec_exit->exit_reason = RMI_EXIT_HOST_CALL;
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000090 } else {
Soby Mathewb4c6df42022-11-09 11:13:29 +000091 /* Copy host call results to host call data structure */
92 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
93 host_call->gprs[i] = rec_entry->gprs[i];
94 }
AlexeiFedorov97844202023-04-27 15:17:35 +010095
96 rec->regs[0] = RSI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +000097 }
98
99 /* Unmap Realm data granule */
100 buffer_unmap(data);
101
102 /* Unlock last level RTT */
103 granule_unlock(walk_result.llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000104}
105
AlexeiFedorov97844202023-04-27 15:17:35 +0100106void handle_rsi_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
107 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000108{
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109 unsigned long ipa = rec->regs[1];
110
AlexeiFedorov97844202023-04-27 15:17:35 +0100111 res->action = UPDATE_REC_RETURN_TO_REALM;
112
Soby Mathewb4c6df42022-11-09 11:13:29 +0000113 if (!ALIGNED(ipa, sizeof(struct rsi_host_call))) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100114 res->smc_res.x[0] = RSI_ERROR_INPUT;
115 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000116 }
117
118 if ((ipa / GRANULE_SIZE) !=
119 ((ipa + sizeof(struct rsi_host_call) - 1UL) / GRANULE_SIZE)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100120 res->smc_res.x[0] = RSI_ERROR_INPUT;
121 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000122 }
123
124 if (!addr_in_rec_par(rec, ipa)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100125 res->smc_res.x[0] = RSI_ERROR_INPUT;
126 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000127 }
128
AlexeiFedorov97844202023-04-27 15:17:35 +0100129 do_host_call(rec, rec_exit, NULL, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000130}
131
132struct rsi_walk_result complete_rsi_host_call(struct rec *rec,
133 struct rmi_rec_entry *rec_entry)
134{
AlexeiFedorov97844202023-04-27 15:17:35 +0100135 struct rsi_result res = { 0UL };
136 struct rsi_walk_result walk_res = { false, 0UL };
Soby Mathewb4c6df42022-11-09 11:13:29 +0000137
138 /*
139 * Do the necessary to walk the S2 RTTs and copy args from NS Host
140 * to the host call data structure. But it is possible for the
141 * RIPAS of the IPA to be EMPTY and hence this call can return
142 * RSI_ERROR_INPUT. In this case, we return RSI_SUCCESS to Realm
143 * and Realm may take an abort on accessing the IPA (depending on
144 * the RIPAS of IPA at that time). This is a situation which can be
145 * controlled from Realm and Realm should avoid this.
146 */
AlexeiFedorov97844202023-04-27 15:17:35 +0100147 do_host_call(rec, NULL, rec_entry, &res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000148
AlexeiFedorov97844202023-04-27 15:17:35 +0100149 if (res.action == STAGE_2_TRANSLATION_FAULT) {
150 walk_res.abort = true;
151 walk_res.rtt_level = res.rtt_level;
152 }
153
154 return walk_res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000155}