blob: 0df0df9985f863eb15b4b56d7a13b5b5b7c82533 [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/**
23 * Sends the number of exceptions handled to the Primary VM.
24 */
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000025void exception_handler_send_exception_count(void)
Fuad Tabbaa48d1222019-12-09 15:42:32 +000026{
J-Alves8304fb92022-06-24 17:14:08 +010027 struct ffa_partition_msg *exception_msg =
28 (struct ffa_partition_msg *)SERVICE_SEND_BUFFER();
Fuad Tabbaa48d1222019-12-09 15:42:32 +000029
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000030 dlog("Sending exception_count %d to primary VM\n",
31 exception_handler_exception_count);
J-Alves8304fb92022-06-24 17:14:08 +010032
33 /*
34 * TODO: remove use of HF_PRIMARY_VM_ID, replace with a mechanism that
35 * allows to detect the caller to a running test service. This may
36 * eventually become to be another endpoint, different from primary VM.
37 */
38 ffa_rxtx_header_init(hf_vm_get_id(), HF_PRIMARY_VM_ID, sizeof(int),
39 &exception_msg->header);
40 memcpy_s(exception_msg->payload, FFA_MSG_PAYLOAD_MAX,
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000041 (const void *)&exception_handler_exception_count,
42 sizeof(exception_handler_exception_count));
J-Alves8304fb92022-06-24 17:14:08 +010043 EXPECT_EQ(ffa_msg_send2(0).func, FFA_SUCCESS_32);
44 ffa_yield();
Fuad Tabbaa48d1222019-12-09 15:42:32 +000045}
46
47/**
48 * Receives the number of exceptions handled.
49 */
J-Alves8304fb92022-06-24 17:14:08 +010050int exception_handler_receive_exception_count(const void *recv_buf)
Fuad Tabbaa48d1222019-12-09 15:42:32 +000051{
J-Alves8304fb92022-06-24 17:14:08 +010052 struct ffa_partition_msg *exception_msg =
53 (struct ffa_partition_msg *)recv_buf;
54 int exception_count = *((const int *)exception_msg->payload);
55 struct ffa_value ret;
56 ffa_notifications_bitmap_t fwk_notif;
Fuad Tabbaa48d1222019-12-09 15:42:32 +000057
J-Alves8304fb92022-06-24 17:14:08 +010058 ret = ffa_notification_get(hf_vm_get_id(), 0,
59 FFA_NOTIFICATION_FLAG_BITMAP_HYP |
60 FFA_NOTIFICATION_FLAG_BITMAP_SPM);
61
62 fwk_notif = ffa_notification_get_from_framework(ret);
J-Alves8304fb92022-06-24 17:14:08 +010063
J-Alves30e26d92022-09-26 12:04:09 +010064 if (fwk_notif == 0U ||
65 exception_msg->header.size != sizeof(exception_count)) {
66 return 0;
67 }
68
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010069 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000070 return exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +000071}
72
J-Alves30e26d92022-09-26 12:04:09 +010073/*
74 * Returns true if the receiver has been preempted by an exception:
75 * - if the receiver is an EL1 partition, it should have sent the exception
76 * count in a message.
77 * - if the receiver is an EL0 partition, the Hyp/SPMC should return FFA_ERROR
78 * with error code FFA_ABORTED.
79 */
80bool exception_received(struct ffa_value *run_res, const void *recv_buf)
81{
82 return exception_handler_receive_exception_count(recv_buf) == 1 ||
83 (run_res->func == FFA_ERROR_32 &&
84 ffa_error_code(*run_res) == FFA_ABORTED);
85}
86
Fuad Tabbaa48d1222019-12-09 15:42:32 +000087/**
88 * EL1 exception handler to use in unit test VMs.
89 * Skips the instruction that triggered the exception.
90 */
91bool exception_handler_skip_instruction(void)
92{
93 dlog("%s function is triggered!\n", __func__);
Fuad Tabbab0ef2a42019-12-19 11:19:25 +000094 ++exception_handler_exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +000095
96 /* Skip instruction that triggered the exception. */
97 uint64_t next_pc = read_msr(elr_el1);
98 next_pc += 4UL;
99 write_msr(elr_el1, next_pc);
100
101 /* Indicate that elr_el1 should not be restored. */
102 return true;
103}
104
105/**
106 * EL1 exception handler to use in unit test VMs.
107 * Yields control back to the hypervisor and sends the number of exceptions.
108 */
Fuad Tabbab86325a2020-01-10 13:38:15 +0000109static bool exception_handler_yield(void)
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000110{
111 dlog("%s function is triggered!\n", __func__);
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000112 ++exception_handler_exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000113
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000114 exception_handler_send_exception_count();
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000115
116 /* Indicate that elr_el1 should not be restored. */
117 return true;
118}
119
120/**
Fuad Tabbab86325a2020-01-10 13:38:15 +0000121 * EL1 exception handler to use in unit test VMs.
122 * Yields control back to the hypervisor and sends the number of exceptions.
123 * Asserts that the Exception Class is Unknown.
124 */
125bool exception_handler_yield_unknown(void)
126{
127 uintreg_t esr_el1 = read_msr(ESR_EL1);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100128 uintreg_t far_el1 = read_msr(FAR_EL1);
129
Fuad Tabbab86325a2020-01-10 13:38:15 +0000130 EXPECT_EQ(GET_ESR_EC(esr_el1), EC_UNKNOWN);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100131
132 /*
133 * For unknown exceptions, the value of far_el1 is UNKNOWN.
134 * Hafnium sets it to 0.
135 */
136 EXPECT_EQ(far_el1, 0);
137
Fuad Tabbab86325a2020-01-10 13:38:15 +0000138 return exception_handler_yield();
139}
140
141/**
142 * EL1 exception handler to use in unit test VMs.
143 * Yields control back to the hypervisor and sends the number of exceptions.
144 * Asserts that the Exception Class is Data Abort (same EL).
145 */
146bool exception_handler_yield_data_abort(void)
147{
148 uintreg_t esr_el1 = read_msr(ESR_EL1);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100149 uintreg_t far_el1 = read_msr(FAR_EL1);
150
Fuad Tabbab86325a2020-01-10 13:38:15 +0000151 EXPECT_EQ(GET_ESR_EC(esr_el1), EC_DATA_ABORT_SAME_EL);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100152 EXPECT_NE(far_el1, 0);
153
Fuad Tabbab86325a2020-01-10 13:38:15 +0000154 return exception_handler_yield();
155}
156
157/**
158 * EL1 exception handler to use in unit test VMs.
159 * Yields control back to the hypervisor and sends the number of exceptions.
160 * Asserts that the Exception Class is Instruction Abort (same EL).
161 */
162bool exception_handler_yield_instruction_abort(void)
163{
164 uintreg_t esr_el1 = read_msr(ESR_EL1);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100165 uintreg_t far_el1 = read_msr(FAR_EL1);
166
Fuad Tabbab86325a2020-01-10 13:38:15 +0000167 EXPECT_EQ(GET_ESR_EC(esr_el1), EC_INSTRUCTION_ABORT_SAME_EL);
Fuad Tabbac3847c72020-08-11 09:32:25 +0100168 EXPECT_NE(far_el1, 0);
169
Fuad Tabbab86325a2020-01-10 13:38:15 +0000170 return exception_handler_yield();
171}
172
173/**
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000174 * Returns the number of times the instruction handler was invoked.
175 */
176int exception_handler_get_num(void)
177{
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000178 return exception_handler_exception_count;
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000179}
180
181/**
182 * Resets the number of exceptions counter;
183 */
184void exception_handler_reset(void)
185{
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000186 exception_handler_exception_count = 0;
Fuad Tabbaa48d1222019-12-09 15:42:32 +0000187}