blob: 24ce7599ecec05e51eee916b477a60de522fb576 [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 */
45 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);
69 host_call = (struct rsi_host_call *)(data + (ipa - page_ipa));
70
71 if (rec_exit != NULL) {
72 /* Copy host call arguments to REC exit data structure */
73 rec_exit->imm = host_call->imm;
74 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
75 rec_exit->gprs[i] = host_call->gprs[i];
76 }
AlexeiFedorov97844202023-04-27 15:17:35 +010077
78 /* Record that a host call is pending */
79 rec->host_call = true;
80
81 /*
82 * Notify the Host.
83 * Leave REC registers unchanged,
84 * these will be read and updated by complete_rsi_host_call.
85 */
86 res->action = EXIT_TO_HOST;
87 rec_exit->exit_reason = RMI_EXIT_HOST_CALL;
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000088 } else {
Soby Mathewb4c6df42022-11-09 11:13:29 +000089 /* Copy host call results to host call data structure */
90 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
91 host_call->gprs[i] = rec_entry->gprs[i];
92 }
AlexeiFedorov97844202023-04-27 15:17:35 +010093
94 rec->regs[0] = RSI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +000095 }
96
97 /* Unmap Realm data granule */
98 buffer_unmap(data);
99
100 /* Unlock last level RTT */
101 granule_unlock(walk_result.llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000102}
103
AlexeiFedorov97844202023-04-27 15:17:35 +0100104void handle_rsi_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
105 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000106{
Soby Mathewb4c6df42022-11-09 11:13:29 +0000107 unsigned long ipa = rec->regs[1];
108
AlexeiFedorov97844202023-04-27 15:17:35 +0100109 res->action = UPDATE_REC_RETURN_TO_REALM;
110
Soby Mathewb4c6df42022-11-09 11:13:29 +0000111 if (!ALIGNED(ipa, sizeof(struct rsi_host_call))) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100112 res->smc_res.x[0] = RSI_ERROR_INPUT;
113 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000114 }
115
116 if ((ipa / GRANULE_SIZE) !=
117 ((ipa + sizeof(struct rsi_host_call) - 1UL) / GRANULE_SIZE)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100118 res->smc_res.x[0] = RSI_ERROR_INPUT;
119 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000120 }
121
122 if (!addr_in_rec_par(rec, ipa)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100123 res->smc_res.x[0] = RSI_ERROR_INPUT;
124 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000125 }
126
AlexeiFedorov97844202023-04-27 15:17:35 +0100127 do_host_call(rec, rec_exit, NULL, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000128}
129
130struct rsi_walk_result complete_rsi_host_call(struct rec *rec,
131 struct rmi_rec_entry *rec_entry)
132{
AlexeiFedorov97844202023-04-27 15:17:35 +0100133 struct rsi_result res = { 0UL };
134 struct rsi_walk_result walk_res = { false, 0UL };
Soby Mathewb4c6df42022-11-09 11:13:29 +0000135
136 /*
137 * Do the necessary to walk the S2 RTTs and copy args from NS Host
138 * to the host call data structure. But it is possible for the
139 * RIPAS of the IPA to be EMPTY and hence this call can return
140 * RSI_ERROR_INPUT. In this case, we return RSI_SUCCESS to Realm
141 * and Realm may take an abort on accessing the IPA (depending on
142 * the RIPAS of IPA at that time). This is a situation which can be
143 * controlled from Realm and Realm should avoid this.
144 */
AlexeiFedorov97844202023-04-27 15:17:35 +0100145 do_host_call(rec, NULL, rec_entry, &res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000146
AlexeiFedorov97844202023-04-27 15:17:35 +0100147 if (res.action == STAGE_2_TRANSLATION_FAULT) {
148 walk_res.abort = true;
149 walk_res.rtt_level = res.rtt_level;
150 }
151
152 return walk_res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000153}