blob: 3a008ef12fefa48bbe570165eff3b30494588731 [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 */
29static unsigned int do_host_call(struct rec *rec,
30 struct rmi_rec_exit *rec_exit,
31 struct rmi_rec_entry *rec_entry,
32 struct rsi_walk_result *rsi_walk_result)
33{
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;
39 unsigned char *data;
40 struct rsi_host_call *host_call;
41 unsigned int i;
42 unsigned int ret = RSI_SUCCESS;
43
44 assert(addr_in_rec_par(rec, ipa));
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000045
46 /* Only 'rec_entry' or 'rec_exit' should be set */
47 assert((rec_entry != NULL) ^ (rec_exit != NULL));
Soby Mathewb4c6df42022-11-09 11:13:29 +000048
Soby Mathewb4c6df42022-11-09 11:13:29 +000049 page_ipa = ipa & GRANULE_MASK;
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +010050 walk_status = realm_ipa_to_pa(rec, page_ipa, &walk_result);
Soby Mathewb4c6df42022-11-09 11:13:29 +000051
52 switch (walk_status) {
53 case WALK_SUCCESS:
54 break;
55 case WALK_FAIL:
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +010056 if (walk_result.ripas_val == RIPAS_EMPTY) {
Soby Mathewb4c6df42022-11-09 11:13:29 +000057 ret = RSI_ERROR_INPUT;
58 } else {
59 rsi_walk_result->abort = true;
60 rsi_walk_result->rtt_level = walk_result.rtt_level;
61 }
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +010062 return ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +000063 case WALK_INVALID_PARAMS:
64 assert(false);
65 break;
66 }
67
68 /* Map Realm data granule to RMM address space */
69 gr = find_granule(walk_result.pa);
70 data = (unsigned char *)granule_map(gr, SLOT_RSI_CALL);
71 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 }
Alexei Fedorov6a15c9e2022-11-16 16:48:12 +000079 } else {
Soby Mathewb4c6df42022-11-09 11:13:29 +000080 /* Copy host call results to host call data structure */
81 for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
82 host_call->gprs[i] = rec_entry->gprs[i];
83 }
84 }
85
86 /* Unmap Realm data granule */
87 buffer_unmap(data);
88
89 /* Unlock last level RTT */
90 granule_unlock(walk_result.llt);
91
Soby Mathewb4c6df42022-11-09 11:13:29 +000092 return ret;
93}
94
AlexeiFedorov5b186ad2023-04-26 14:43:18 +010095struct rsi_result handle_rsi_host_call(struct rec *rec,
96 struct rmi_rec_exit *rec_exit)
Soby Mathewb4c6df42022-11-09 11:13:29 +000097{
AlexeiFedorov5b186ad2023-04-26 14:43:18 +010098 struct rsi_result res = { 0 };
Soby Mathewb4c6df42022-11-09 11:13:29 +000099 unsigned long ipa = rec->regs[1];
100
101 if (!ALIGNED(ipa, sizeof(struct rsi_host_call))) {
AlexeiFedorov5b186ad2023-04-26 14:43:18 +0100102 res.smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000103 return res;
104 }
105
106 if ((ipa / GRANULE_SIZE) !=
107 ((ipa + sizeof(struct rsi_host_call) - 1UL) / GRANULE_SIZE)) {
AlexeiFedorov5b186ad2023-04-26 14:43:18 +0100108 res.smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109 return res;
110 }
111
112 if (!addr_in_rec_par(rec, ipa)) {
AlexeiFedorov5b186ad2023-04-26 14:43:18 +0100113 res.smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000114 return res;
115 }
116
AlexeiFedorov5b186ad2023-04-26 14:43:18 +0100117 res.smc_res.x[0] = do_host_call(rec, rec_exit, NULL, &res.walk_result);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000118
119 return res;
120}
121
122struct rsi_walk_result complete_rsi_host_call(struct rec *rec,
123 struct rmi_rec_entry *rec_entry)
124{
125 struct rsi_walk_result res = { false, 0UL };
126
127 /*
128 * Do the necessary to walk the S2 RTTs and copy args from NS Host
129 * to the host call data structure. But it is possible for the
130 * RIPAS of the IPA to be EMPTY and hence this call can return
131 * RSI_ERROR_INPUT. In this case, we return RSI_SUCCESS to Realm
132 * and Realm may take an abort on accessing the IPA (depending on
133 * the RIPAS of IPA at that time). This is a situation which can be
134 * controlled from Realm and Realm should avoid this.
135 */
136 (void)do_host_call(rec, NULL, rec_entry, &res);
137
138 return res;
139}