blob: 23ff16746f4cd04d8e12d43d2b0c5c0f4eeb9de9 [file] [log] [blame]
Fuad Tabbaa48d1222019-12-09 15:42:32 +00001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
Fuad Tabbaa48d1222019-12-09 15:42:32 +00007 */
8
9#include "hf/dlog.h"
10
11#include "vmapi/hf/call.h"
12
13#include "../msr.h"
Fuad Tabbab86325a2020-01-10 13:38:15 +000014#include "sysregs.h"
Fuad Tabbaa48d1222019-12-09 15:42:32 +000015#include "test/hftest.h"
16
17/**
18 * Tracks the number of times the exception handler has been invoked.
19 */
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000020static int exception_handler_exception_count = 0;
Fuad Tabbaa48d1222019-12-09 15:42:32 +000021
22/**
Madhukar Pappireddyf054a052022-12-22 11:37:11 -060023 * Tracks the virtual interrupt that was last handled by SP.
24 */
25static uint32_t last_serviced_interrupt = 0;
26
27/**
Kathleen Capella4eba3f32022-12-09 18:05:51 -050028 * Used to specify an instruction address to return to after exception
29 * is handled.
30 */
31static uint64_t exception_handler_return_addr = 0;
32
33/**
Fuad Tabbaa48d1222019-12-09 15:42:32 +000034 * Sends the number of exceptions handled to the Primary VM.
35 */
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000036void exception_handler_send_exception_count(void)
Fuad Tabbaa48d1222019-12-09 15:42:32 +000037{
J-Alves8304fb92022-06-24 17:14:08 +010038 struct ffa_partition_msg *exception_msg =
39 (struct ffa_partition_msg *)SERVICE_SEND_BUFFER();
Fuad Tabbaa48d1222019-12-09 15:42:32 +000040
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000041 dlog("Sending exception_count %d to primary VM\n",
42 exception_handler_exception_count);
J-Alves8304fb92022-06-24 17:14:08 +010043
44 /*
45 * TODO: remove use of HF_PRIMARY_VM_ID, replace with a mechanism that
46 * allows to detect the caller to a running test service. This may
47 * eventually become to be another endpoint, different from primary VM.
48 */
49 ffa_rxtx_header_init(hf_vm_get_id(), HF_PRIMARY_VM_ID, sizeof(int),
50 &exception_msg->header);
51 memcpy_s(exception_msg->payload, FFA_MSG_PAYLOAD_MAX,
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000052 (const void *)&exception_handler_exception_count,
53 sizeof(exception_handler_exception_count));
J-Alves8304fb92022-06-24 17:14:08 +010054 EXPECT_EQ(ffa_msg_send2(0).func, FFA_SUCCESS_32);
55 ffa_yield();
Fuad Tabbaa48d1222019-12-09 15:42:32 +000056}
57
58/**
59 * Receives the number of exceptions handled.
60 */
J-Alves8304fb92022-06-24 17:14:08 +010061int exception_handler_receive_exception_count(const void *recv_buf)
Fuad Tabbaa48d1222019-12-09 15:42:32 +000062{
J-Alves8304fb92022-06-24 17:14:08 +010063 struct ffa_partition_msg *exception_msg =
64 (struct ffa_partition_msg *)recv_buf;
65 int exception_count = *((const int *)exception_msg->payload);
66 struct ffa_value ret;
67 ffa_notifications_bitmap_t fwk_notif;
Fuad Tabbaa48d1222019-12-09 15:42:32 +000068
J-Alves8304fb92022-06-24 17:14:08 +010069 ret = ffa_notification_get(hf_vm_get_id(), 0,
70 FFA_NOTIFICATION_FLAG_BITMAP_HYP |
71 FFA_NOTIFICATION_FLAG_BITMAP_SPM);
72
73 fwk_notif = ffa_notification_get_from_framework(ret);
J-Alves8304fb92022-06-24 17:14:08 +010074
J-Alves30e26d92022-09-26 12:04:09 +010075 if (fwk_notif == 0U ||
76 exception_msg->header.size != sizeof(exception_count)) {
77 return 0;
78 }
79
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010080 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000081 return exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +000082}
83
J-Alves30e26d92022-09-26 12:04:09 +010084/*
85 * Returns true if the receiver has been preempted by an exception:
86 * - if the receiver is an EL1 partition, it should have sent the exception
87 * count in a message.
88 * - if the receiver is an EL0 partition, the Hyp/SPMC should return FFA_ERROR
89 * with error code FFA_ABORTED.
90 */
91bool exception_received(struct ffa_value *run_res, const void *recv_buf)
92{
93 return exception_handler_receive_exception_count(recv_buf) == 1 ||
94 (run_res->func == FFA_ERROR_32 &&
95 ffa_error_code(*run_res) == FFA_ABORTED);
96}
97
Fuad Tabbaa48d1222019-12-09 15:42:32 +000098/**
99 * EL1 exception handler to use in unit test VMs.
100 * Skips the instruction that triggered the exception.
101 */
102bool exception_handler_skip_instruction(void)
103{
104 dlog("%s function is triggered!\n", __func__);
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000105 ++exception_handler_exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000106
107 /* Skip instruction that triggered the exception. */
108 uint64_t next_pc = read_msr(elr_el1);
109 next_pc += 4UL;
110 write_msr(elr_el1, next_pc);
111
112 /* Indicate that elr_el1 should not be restored. */
113 return true;
114}
115
116/**
Kathleen Capella4eba3f32022-12-09 18:05:51 -0500117 * Warning: Intended to be used only in test code.
118 * The ability to jump to any address after an exception could
119 * possibily be exploited by malicious code.
120 *
121 * Sets the specified instruction address to return to after handler exits.
122 */
123void exception_handler_set_return_addr(uint64_t instr_addr)
124{
125 exception_handler_return_addr = instr_addr;
126}
127
128/**
129 * Returns the specified instruction address to return to after handler exits.
130 */
131static uint64_t exception_handler_get_return_addr(void)
132{
133 return exception_handler_return_addr;
134}
135
136/**
137 * EL1 exception handler to use in unit test VMs.
138 * Skips to the instruction address specified in general
139 * register x19.
140 */
141bool exception_handler_skip_to_instruction(void)
142{
143 dlog("%s function is triggered!\n", __func__);
144 ++exception_handler_exception_count;
145
146 uint64_t instr_addr = exception_handler_get_return_addr();
147
148 if (instr_addr) {
149 write_msr(elr_el1, instr_addr);
150 /* Indicate that elr_el1 should not be restored. */
151 return true;
152 }
153
154 dlog_error("%s: Return address not set, restoring elr_el1\n", __func__);
155 return false;
156}
157
158/**
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000159 * EL1 exception handler to use in unit test VMs.
160 * Yields control back to the hypervisor and sends the number of exceptions.
161 */
Fuad Tabbab86325a2020-01-10 13:38:15 +0000162static bool exception_handler_yield(void)
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000163{
164 dlog("%s function is triggered!\n", __func__);
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000165 ++exception_handler_exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000166
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000167 exception_handler_send_exception_count();
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000168
169 /* Indicate that elr_el1 should not be restored. */
170 return true;
171}
172
173/**
Fuad Tabbab86325a2020-01-10 13:38:15 +0000174 * EL1 exception handler to use in unit test VMs.
175 * Yields control back to the hypervisor and sends the number of exceptions.
176 * Asserts that the Exception Class is Unknown.
177 */
178bool exception_handler_yield_unknown(void)
179{
180 uintreg_t esr_el1 = read_msr(ESR_EL1);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100181 uintreg_t far_el1 = read_msr(FAR_EL1);
182
Fuad Tabbab86325a2020-01-10 13:38:15 +0000183 EXPECT_EQ(GET_ESR_EC(esr_el1), EC_UNKNOWN);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100184
185 /*
186 * For unknown exceptions, the value of far_el1 is UNKNOWN.
187 * Hafnium sets it to 0.
188 */
189 EXPECT_EQ(far_el1, 0);
190
Fuad Tabbab86325a2020-01-10 13:38:15 +0000191 return exception_handler_yield();
192}
193
194/**
195 * EL1 exception handler to use in unit test VMs.
196 * Yields control back to the hypervisor and sends the number of exceptions.
197 * Asserts that the Exception Class is Data Abort (same EL).
198 */
199bool exception_handler_yield_data_abort(void)
200{
201 uintreg_t esr_el1 = read_msr(ESR_EL1);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100202 uintreg_t far_el1 = read_msr(FAR_EL1);
203
Fuad Tabbab86325a2020-01-10 13:38:15 +0000204 EXPECT_EQ(GET_ESR_EC(esr_el1), EC_DATA_ABORT_SAME_EL);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100205 EXPECT_NE(far_el1, 0);
206
Fuad Tabbab86325a2020-01-10 13:38:15 +0000207 return exception_handler_yield();
208}
209
210/**
211 * EL1 exception handler to use in unit test VMs.
212 * Yields control back to the hypervisor and sends the number of exceptions.
213 * Asserts that the Exception Class is Instruction Abort (same EL).
214 */
215bool exception_handler_yield_instruction_abort(void)
216{
217 uintreg_t esr_el1 = read_msr(ESR_EL1);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100218 uintreg_t far_el1 = read_msr(FAR_EL1);
219
Fuad Tabbab86325a2020-01-10 13:38:15 +0000220 EXPECT_EQ(GET_ESR_EC(esr_el1), EC_INSTRUCTION_ABORT_SAME_EL);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100221 EXPECT_NE(far_el1, 0);
222
Fuad Tabbab86325a2020-01-10 13:38:15 +0000223 return exception_handler_yield();
224}
225
226/**
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000227 * Returns the number of times the instruction handler was invoked.
228 */
229int exception_handler_get_num(void)
230{
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000231 return exception_handler_exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000232}
233
234/**
235 * Resets the number of exceptions counter;
236 */
237void exception_handler_reset(void)
238{
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000239 exception_handler_exception_count = 0;
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000240}
Madhukar Pappireddyf054a052022-12-22 11:37:11 -0600241
242/**
243 * Updates the last serviced virtual interrupt ID.
244 */
245void exception_handler_set_last_interrupt(uint32_t id)
246{
247 last_serviced_interrupt = id;
248}
249
250/**
251 * Returns the last serviced virtual interrupt ID.
252 */
253uint32_t exception_handler_get_last_interrupt(void)
254{
255 return last_serviced_interrupt;
256}